Transaction Hash:
Block:
19437976 at Mar-15-2024 04:29:23 AM +UTC
Transaction Fee:
0.002312372372559444 ETH
$8.81
Gas Used:
46,722 Gas / 49.492153002 Gwei
Emitted Events:
129 |
TBTCToken.Transfer( from=[Sender] 0x0b39a46d9fe2f26ffe03c5f32fdf19541e1e92c8, to=Avocado, value=500000000000000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x0b39a46D...41e1e92C8 |
0.006465937385166013 Eth
Nonce: 2000
|
0.004153565012606569 Eth
Nonce: 2001
| 0.002312372372559444 | ||
0x8dAEBADE...f50815fAa | |||||
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 7.783070038235651444 Eth | 7.783074710435651444 Eth | 0.0000046722 |
Execution Trace
TBTCToken.transfer( recipient=0x9A1546f5B39203B2B40c9382b0E76370028e8e01, amount=500000000000000 ) => ( True )
transfer[ERC20 (ln:117)]
_transfer[ERC20 (ln:118)]
sub[ERC20 (ln:206)]
add[ERC20 (ln:207)]
Transfer[ERC20 (ln:208)]
File 1 of 2: TBTCToken
File 2 of 2: Avocado
pragma solidity 0.5.17; import {ERC20} from "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; import {ERC20Detailed} from "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol"; import {VendingMachineAuthority} from "./VendingMachineAuthority.sol"; import {ITokenRecipient} from "../interfaces/ITokenRecipient.sol"; /// @title TBTC Token. /// @notice This is the TBTC ERC20 contract. /// @dev Tokens can only be minted by the `VendingMachine` contract. contract TBTCToken is ERC20Detailed, ERC20, VendingMachineAuthority { /// @dev Constructor, calls ERC20Detailed constructor to set Token info /// ERC20Detailed(TokenName, TokenSymbol, NumberOfDecimals) constructor(address _VendingMachine) ERC20Detailed("tBTC", "TBTC", 18) VendingMachineAuthority(_VendingMachine) public { // solium-disable-previous-line no-empty-blocks } /// @dev Mints an amount of the token and assigns it to an account. /// Uses the internal _mint function. /// @param _account The account that will receive the created tokens. /// @param _amount The amount of tokens that will be created. function mint(address _account, uint256 _amount) external onlyVendingMachine returns (bool) { // NOTE: this is a public function with unchecked minting. Only the // vending machine is allowed to call it, and it is in charge of // ensuring minting is permitted. _mint(_account, _amount); return true; } /// @dev Burns an amount of the token from the given account's balance. /// deducting from the sender's allowance for said account. /// Uses the internal _burn function. /// @param _account The account whose tokens will be burnt. /// @param _amount The amount of tokens that will be burnt. function burnFrom(address _account, uint256 _amount) external { _burnFrom(_account, _amount); } /// @dev Destroys `amount` tokens from `msg.sender`, reducing the /// total supply. /// @param _amount The amount of tokens that will be burnt. function burn(uint256 _amount) external { _burn(msg.sender, _amount); } /// @notice Set allowance for other address and notify. /// Allows `_spender` to spend no more than `_value` /// tokens on your behalf and then ping the contract about /// it. /// @dev The `_spender` should implement the `ITokenRecipient` /// interface to receive approval notifications. /// @param _spender Address of contract authorized to spend. /// @param _value The max amount they can spend. /// @param _extraData Extra information to send to the approved contract. /// @return true if the `_spender` was successfully approved and acted on /// the approval, false (or revert) otherwise. function approveAndCall( ITokenRecipient _spender, uint256 _value, bytes memory _extraData ) public returns (bool) { // not external to allow bytes memory parameters if (approve(address(_spender), _value)) { _spender.receiveApproval(msg.sender, _value, address(this), _extraData); return true; } return false; } } pragma solidity ^0.5.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; /** * @dev Implementation of the `IERC20` interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using `_mint`. * For a generic mechanism see `ERC20Mintable`. * * *For a detailed writeup see our guide [How to implement supply * mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).* * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an `Approval` event is emitted on calls to `transferFrom`. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard `decreaseAllowance` and `increaseAllowance` * functions have been added to mitigate the well-known issues around setting * allowances. See `IERC20.approve`. */ contract ERC20 is IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See `IERC20.totalSupply`. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See `IERC20.balanceOf`. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See `IERC20.transfer`. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(msg.sender, recipient, amount); return true; } /** * @dev See `IERC20.allowance`. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See `IERC20.approve`. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public returns (bool) { _approve(msg.sender, spender, value); return true; } /** * @dev See `IERC20.transferFrom`. * * Emits an `Approval` event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of `ERC20`; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `value`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount)); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to `approve` that can be used as a mitigation for * problems described in `IERC20.approve`. * * Emits an `Approval` event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to `approve` that can be used as a mitigation for * problems described in `IERC20.approve`. * * Emits an `Approval` event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue)); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to `transfer`, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a `Transfer` event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a `Transfer` event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destoys `amount` tokens from `account`, reducing the * total supply. * * Emits a `Transfer` event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 value) internal { require(account != address(0), "ERC20: burn from the zero address"); _totalSupply = _totalSupply.sub(value); _balances[account] = _balances[account].sub(value); emit Transfer(account, address(0), value); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an `Approval` event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 value) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = value; emit Approval(owner, spender, value); } /** * @dev Destoys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See `_burn` and `_approve`. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, msg.sender, _allowances[account][msg.sender].sub(amount)); } } pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see `ERC20Detailed`. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a `Transfer` event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through `transferFrom`. This is * zero by default. * * This value changes when `approve` or `transferFrom` are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * > Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an `Approval` event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a `Transfer` event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to `approve`. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } pragma solidity ^0.5.0; import "./IERC20.sol"; /** * @dev Optional functions from the ERC20 standard. */ contract ERC20Detailed is IERC20 { string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of * these values are immutable: they can only be set once during * construction. */ constructor (string memory name, string memory symbol, uint8 decimals) public { _name = name; _symbol = symbol; _decimals = decimals; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. * * > Note that this information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * `IERC20.balanceOf` and `IERC20.transfer`. */ function decimals() public view returns (uint8) { return _decimals; } } pragma solidity 0.5.17; /// @title Vending Machine Authority. /// @notice Contract to secure function calls to the Vending Machine. /// @dev Secured by setting the VendingMachine address and using the /// onlyVendingMachine modifier on functions requiring restriction. contract VendingMachineAuthority { address internal VendingMachine; constructor(address _vendingMachine) public { VendingMachine = _vendingMachine; } /// @notice Function modifier ensures modified function caller address is the vending machine. modifier onlyVendingMachine() { require(msg.sender == VendingMachine, "caller must be the vending machine"); _; } } pragma solidity 0.5.17; /// @title Interface of recipient contract for `approveAndCall` pattern. /// Implementors will be able to be used in an `approveAndCall` /// interaction with a supporting contract, such that a token approval /// can call the contract acting on that approval in a single /// transaction. /// /// See the `FundingScript` and `RedemptionScript` contracts as examples. interface ITokenRecipient { /// Typically called from a token contract's `approveAndCall` method, this /// method will receive the original owner of the token (`_from`), the /// transferred `_value` (in the case of an ERC721, the token id), the token /// address (`_token`), and a blob of `_extraData` that is informally /// specified by the implementor of this method as a way to communicate /// additional parameters. /// /// Token calls to `receiveApproval` should revert if `receiveApproval` /// reverts, and reverts should remove the approval. /// /// @param _from The original owner of the token approved for transfer. /// @param _value For an ERC20, the amount approved for transfer; for an /// ERC721, the id of the token approved for transfer. /// @param _token The address of the contract for the token whose transfer /// was approved. /// @param _extraData An additional data blob forwarded unmodified through /// `approveAndCall`, used to allow the token owner to pass /// additional parameters and data to this method. The structure of /// the extra data is informally specified by the implementor of /// this interface. function receiveApproval( address _from, uint256 _value, address _token, bytes calldata _extraData ) external; } pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } }
File 2 of 2: Avocado
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; /// @title IAvocado /// @notice interface to access internal vars on-chain interface IAvocado { function _avoImpl() external view returns (address); function _data() external view returns (uint256); function _owner() external view returns (address); } /// @title Avocado /// @notice Proxy for Avocados as deployed by the AvoFactory. /// Basic Proxy with fallback to delegate and address for implementation contract at storage 0x0 // // @dev If this contract changes then the deployment addresses for new Avocados through factory change too!! // Relayers might want to pass in version as new param then to forward to the correct factory contract Avocado { /// @notice flexible immutable data slot. /// first 20 bytes: address owner /// next 4 bytes: uint32 index /// next 1 byte: uint8 type /// next 9 bytes: used flexible for use-cases found in the future uint256 internal immutable _data; /// @notice address of the Avocado logic / implementation contract. IMPORTANT: SAME STORAGE SLOT AS FOR PROXY // // @dev _avoImpl MUST ALWAYS be the first declared variable here in the proxy and in the logic contract // when upgrading, the storage at memory address 0x0 is upgraded (first slot). // To reduce deployment costs this variable is internal but can still be retrieved with // _avoImpl(), see code and comments in fallback below address internal _avoImpl; /// @notice sets _avoImpl & immutable _data, fetching it from msg.sender. // // @dev those values are not input params to not influence the deterministic Create2 address! constructor() { // "\\x8c\\x65\\x73\\x89" is hardcoded bytes of function selector for transientDeployData() (, bytes memory deployData_) = msg.sender.staticcall(bytes("\\x8c\\x65\\x73\\x89")); address impl_; uint256 data_; assembly { // cast first 20 bytes to version address (_avoImpl) impl_ := mload(add(deployData_, 0x20)) // cast bytes in position 0x40 to uint256 data; deployData_ plus 0x40 due to padding data_ := mload(add(deployData_, 0x40)) } _data = data_; _avoImpl = impl_; } /// @notice Delegates the current call to `_avoImpl` unless one of the view methods is called: /// `_avoImpl()` returns the address for `_avoImpl`, `_owner()` returns the first /// 20 bytes of `_data`, `_data()` returns `_data`. // // @dev Mostly based on OpenZeppelin Proxy.sol // logic contract must not implement a function `_avoImpl()`, `_owner()` or `_data()` // as they will not be callable due to collision fallback() external payable { uint256 data_ = _data; assembly { let functionSelector_ := calldataload(0) // 0xb2bdfa7b = function selector for _owner() if eq(functionSelector_, 0xb2bdfa7b00000000000000000000000000000000000000000000000000000000) { // store address owner at memory address 0x0, loading only last 20 bytes through the & mask mstore(0, and(data_, 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff)) return(0, 0x20) // send 32 bytes of memory slot 0 as return value } // 0x68beab3f = function selector for _data() if eq(functionSelector_, 0x68beab3f00000000000000000000000000000000000000000000000000000000) { mstore(0, data_) // store uint256 _data at memory address 0x0 return(0, 0x20) // send 32 bytes of memory slot 0 as return value } // load address avoImpl_ from storage let avoImpl_ := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff) // first 4 bytes of calldata specify which function to call. // if those first 4 bytes == 874095c6 (function selector for _avoImpl()) then we return the _avoImpl address // The value is right padded to 32-bytes with 0s if eq(functionSelector_, 0x874095c600000000000000000000000000000000000000000000000000000000) { mstore(0, avoImpl_) // store address avoImpl_ at memory address 0x0 return(0, 0x20) // send 32 bytes of memory slot 0 as return value } // @dev code below is taken from OpenZeppelin Proxy.sol _delegate function // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), avoImpl_, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } }