Transaction Hash:
Block:
12062912 at Mar-18-2021 01:24:46 PM +UTC
Transaction Fee:
0.0112305765 ETH
$43.15
Gas Used:
52,357 Gas / 214.5 Gwei
Emitted Events:
182 |
CoinvestToken.Transfer( from=[Sender] 0xb5367dc03381e33c61457134c1ddeaff97bb15fe, to=0x626EC4c9C954BFe77308d54b7fA397257305BBAD, tokens=300000000000000000000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x5e8F8559...22291B06d | |||||
0xb5367dC0...F97BB15Fe |
0.019328143 Eth
Nonce: 35
|
0.0080975665 Eth
Nonce: 36
| 0.0112305765 | ||
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 1,038.187194650906429449 Eth | 1,038.198425227406429449 Eth | 0.0112305765 |
Execution Trace
CoinvestToken.transfer( _to=0x626EC4c9C954BFe77308d54b7fA397257305BBAD, _amount=300000000000000000000 ) => ( success=True )
transfer[CoinvestToken (ln:190)]
pragma solidity ^0.4.20; /** * @title SafeMath * @dev Math operations with safety checks that throw on error **/ library SafeMathLib{ function mul(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a * b; assert(a == 0 || c / a == b); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". **/ contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() public { owner = 0x4e70812b550687692e18F53445C601458228aFfD; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) onlyOwner public { require(newOwner != address(0)); emit OwnershipTransferred(owner, newOwner); owner = newOwner; } } /** * @dev Contract used to deploy COIN V2 and allow users to swap V1 for V2. **/ contract TokenSwap { // Address of the old Coinvest COIN token. address public constant OLD_TOKEN = 0x4306ce4a5d8b21ee158cb8396a4f6866f14d6ac8; // Address of the new COINVEST COIN V2 token (to be launched on construction). CoinvestToken public newToken; constructor() public { newToken = new CoinvestToken(); } /** * @dev Only function. ERC223 transfer from old token to this contract calls this. * @param _from The address that has transferred this contract tokens. * @param _value The amount of tokens that have been transferred. * @param _data The extra data sent with transfer (should be nothing). **/ function tokenFallback(address _from, uint _value, bytes _data) external { require(msg.sender == OLD_TOKEN); // Ensure caller is old token contract. require(newToken.transfer(_from, _value)); // Transfer new tokens to sender. } } /** * @dev Abstract contract for approveAndCall. **/ contract ApproveAndCallFallBack { function receiveApproval(address from, uint256 tokens, address token, bytes data) public; } /** * @title Coinvest COIN Token * @dev ERC20 contract utilizing ERC865-ish structure (3esmit's implementation with alterations). * @dev to allow users to pay Ethereum fees in tokens. **/ contract CoinvestToken is Ownable { using SafeMathLib for uint256; string public constant symbol = "COIN"; string public constant name = "Coinvest COIN V2 Token"; uint8 public constant decimals = 18; uint256 private _totalSupply = 107142857 * (10 ** 18); // Function sigs to be used within contract for signature recovery. bytes4 internal constant transferSig = 0xa9059cbb; bytes4 internal constant approveSig = 0x095ea7b3; bytes4 internal constant increaseApprovalSig = 0xd73dd623; bytes4 internal constant decreaseApprovalSig = 0x66188463; bytes4 internal constant approveAndCallSig = 0xcae9ca51; bytes4 internal constant revokeSignatureSig = 0xe40d89e5; // Balances for each account mapping(address => uint256) balances; // Owner of account approves the transfer of an amount to another account mapping(address => mapping (address => uint256)) allowed; // Keeps track of the last nonce sent from user. Used for delegated functions. mapping (address => uint256) nonces; // Mapping of past used hashes: true if already used. mapping (address => mapping (bytes => bool)) invalidSignatures; // Mapping of finalized ERC865 standard sigs => our function sigs for future-proofing mapping (bytes4 => bytes4) public standardSigs; event Transfer(address indexed from, address indexed to, uint tokens); event Approval(address indexed from, address indexed spender, uint tokens); event SignatureRedeemed(bytes _sig, address indexed from); /** * @dev Set owner and beginning balance. **/ constructor() public { balances[msg.sender] = _totalSupply; } /** * @dev This code allows us to redirect pre-signed calls with different function selectors to our own. **/ function () public { bytes memory calldata = msg.data; bytes4 new_selector = standardSigs[msg.sig]; require(new_selector != 0); assembly { mstore(add(0x20, calldata), new_selector) } require(address(this).delegatecall(calldata)); assembly { if iszero(eq(returndatasize, 0x20)) { revert(0, 0) } returndatacopy(0, 0, returndatasize) return(0, returndatasize) } } /** ******************************** ERC20 ********************************* **/ /** * @dev Transfers coins from one address to another. * @param _to The recipient of the transfer amount. * @param _amount The amount of tokens to transfer. **/ function transfer(address _to, uint256 _amount) public returns (bool success) { require(_transfer(msg.sender, _to, _amount)); return true; } /** * @dev An allowed address can transfer tokens from another's address. * @param _from The owner of the tokens to be transferred. * @param _to The address to which the tokens will be transferred. * @param _amount The amount of tokens to be transferred. **/ function transferFrom(address _from, address _to, uint _amount) public returns (bool success) { require(balances[_from] >= _amount && allowed[_from][msg.sender] >= _amount); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_amount); require(_transfer(_from, _to, _amount)); return true; } /** * @dev Approves a wallet to transfer tokens on one's behalf. * @param _spender The wallet approved to spend tokens. * @param _amount The amount of tokens approved to spend. **/ function approve(address _spender, uint256 _amount) public returns (bool success) { require(_approve(msg.sender, _spender, _amount)); return true; } /** * @dev Increases the allowed amount for spender from msg.sender. * @param _spender The address to increase allowed amount for. * @param _amount The amount of tokens to increase allowed amount by. **/ function increaseApproval(address _spender, uint256 _amount) public returns (bool success) { require(_increaseApproval(msg.sender, _spender, _amount)); return true; } /** * @dev Decreases the allowed amount for spender from msg.sender. * @param _spender The address to decrease allowed amount for. * @param _amount The amount of tokens to decrease allowed amount by. **/ function decreaseApproval(address _spender, uint256 _amount) public returns (bool success) { require(_decreaseApproval(msg.sender, _spender, _amount)); return true; } /** * @dev Used to approve an address and call a function on it in the same transaction. * @dev _spender The address to be approved to spend COIN. * @dev _amount The amount of COIN to be approved to spend. * @dev _data The data to send to the called contract. **/ function approveAndCall(address _spender, uint256 _amount, bytes _data) public returns (bool success) { require(_approve(msg.sender, _spender, _amount)); ApproveAndCallFallBack(_spender).receiveApproval(msg.sender, _amount, address(this), _data); return true; } /** ****************************** Internal ******************************** **/ /** * @dev Internal transfer for all functions that transfer. * @param _from The address that is transferring coins. * @param _to The receiving address of the coins. * @param _amount The amount of coins being transferred. **/ function _transfer(address _from, address _to, uint256 _amount) internal returns (bool success) { require (_to != address(0)); require(balances[_from] >= _amount); balances[_from] = balances[_from].sub(_amount); balances[_to] = balances[_to].add(_amount); emit Transfer(_from, _to, _amount); return true; } /** * @dev Internal approve for all functions that require an approve. * @param _owner The owner who is allowing spender to use their balance. * @param _spender The wallet approved to spend tokens. * @param _amount The amount of tokens approved to spend. **/ function _approve(address _owner, address _spender, uint256 _amount) internal returns (bool success) { allowed[_owner][_spender] = _amount; emit Approval(_owner, _spender, _amount); return true; } /** * @dev Increases the allowed by "_amount" for "_spender" from "owner" * @param _owner The address that tokens may be transferred from. * @param _spender The address that may transfer these tokens. * @param _amount The amount of tokens to transfer. **/ function _increaseApproval(address _owner, address _spender, uint256 _amount) internal returns (bool success) { allowed[_owner][_spender] = allowed[_owner][_spender].add(_amount); emit Approval(_owner, _spender, allowed[_owner][_spender]); return true; } /** * @dev Decreases the allowed by "_amount" for "_spender" from "_owner" * @param _owner The owner of the tokens to decrease allowed for. * @param _spender The spender whose allowed will decrease. * @param _amount The amount of tokens to decrease allowed by. **/ function _decreaseApproval(address _owner, address _spender, uint256 _amount) internal returns (bool success) { if (allowed[_owner][_spender] <= _amount) allowed[_owner][_spender] = 0; else allowed[_owner][_spender] = allowed[_owner][_spender].sub(_amount); emit Approval(_owner, _spender, allowed[_owner][_spender]); return true; } /** ************************ Delegated Functions *************************** **/ /** * @dev Called by delegate with a signed hash of the transaction data to allow a user * @dev to transfer tokens without paying gas in Ether (they pay in COIN instead). * @param _signature Signed hash of data for this transfer. * @param _to The address to transfer COIN to. * @param _value The amount of COIN to transfer. * @param _gasPrice Price (IN COIN) that will be paid per unit of gas by user to "delegate". * @param _nonce Nonce of the user's new transaction. **/ function transferPreSigned( bytes _signature, address _to, uint256 _value, uint256 _gasPrice, uint256 _nonce) public validPayload(292) returns (bool) { // Log starting gas left of transaction for later gas price calculations. uint256 gas = gasleft(); // Recover signer address from signature; ensure address is valid. address from = recoverPreSigned(_signature, transferSig, _to, _value, "", _gasPrice, _nonce); require(from != address(0)); // Require the hash has not been used, declare it used, increment nonce. require(!invalidSignatures[from][_signature]); invalidSignatures[from][_signature] = true; nonces[from]++; // Internal transfer. require(_transfer(from, _to, _value)); // If the delegate is charging, pay them for gas in COIN. if (_gasPrice > 0) { // 35000 because of base fee of 21000 and ~14000 for the fee transfer. gas = 35000 + gas.sub(gasleft()); require(_transfer(from, msg.sender, _gasPrice.mul(gas))); } emit SignatureRedeemed(_signature, from); return true; } /** * @dev Called by a delegate with signed hash to approve a transaction for user. * @dev All variables equivalent to transfer except _to: * @param _to The address that will be approved to transfer COIN from user's wallet. **/ function approvePreSigned( bytes _signature, address _to, uint256 _value, uint256 _gasPrice, uint256 _nonce) public validPayload(292) returns (bool) { uint256 gas = gasleft(); address from = recoverPreSigned(_signature, approveSig, _to, _value, "", _gasPrice, _nonce); require(from != address(0)); require(!invalidSignatures[from][_signature]); invalidSignatures[from][_signature] = true; nonces[from]++; require(_approve(from, _to, _value)); if (_gasPrice > 0) { gas = 35000 + gas.sub(gasleft()); require(_transfer(from, msg.sender, _gasPrice.mul(gas))); } emit SignatureRedeemed(_signature, from); return true; } /** * @dev Used to increase the amount allowed for "_to" to spend from "from" * @dev A bare approve allows potentially nasty race conditions when using a delegate. **/ function increaseApprovalPreSigned( bytes _signature, address _to, uint256 _value, uint256 _gasPrice, uint256 _nonce) public validPayload(292) returns (bool) { uint256 gas = gasleft(); address from = recoverPreSigned(_signature, increaseApprovalSig, _to, _value, "", _gasPrice, _nonce); require(from != address(0)); require(!invalidSignatures[from][_signature]); invalidSignatures[from][_signature] = true; nonces[from]++; require(_increaseApproval(from, _to, _value)); if (_gasPrice > 0) { gas = 35000 + gas.sub(gasleft()); require(_transfer(from, msg.sender, _gasPrice.mul(gas))); } emit SignatureRedeemed(_signature, from); return true; } /** * @dev Added for the same reason as increaseApproval. Decreases to 0 if "_value" is greater than allowed. **/ function decreaseApprovalPreSigned( bytes _signature, address _to, uint256 _value, uint256 _gasPrice, uint256 _nonce) public validPayload(292) returns (bool) { uint256 gas = gasleft(); address from = recoverPreSigned(_signature, decreaseApprovalSig, _to, _value, "", _gasPrice, _nonce); require(from != address(0)); require(!invalidSignatures[from][_signature]); invalidSignatures[from][_signature] = true; nonces[from]++; require(_decreaseApproval(from, _to, _value)); if (_gasPrice > 0) { gas = 35000 + gas.sub(gasleft()); require(_transfer(from, msg.sender, _gasPrice.mul(gas))); } emit SignatureRedeemed(_signature, from); return true; } /** * @dev approveAndCallPreSigned allows a user to approve a contract and call a function on it * @dev in the same transaction. As with the other presigneds, a delegate calls this with signed data from user. * @dev This function is the big reason we're using gas price and calculating gas use. * @dev Using this with the investment contract can result in varying gas costs. * @param _extraData The data to send to the contract. **/ function approveAndCallPreSigned( bytes _signature, address _to, uint256 _value, bytes _extraData, uint256 _gasPrice, uint256 _nonce) public validPayload(356) returns (bool) { uint256 gas = gasleft(); address from = recoverPreSigned(_signature, approveAndCallSig, _to, _value, _extraData, _gasPrice, _nonce); require(from != address(0)); require(!invalidSignatures[from][_signature]); invalidSignatures[from][_signature] = true; nonces[from]++; require(_approve(from, _to, _value)); ApproveAndCallFallBack(_to).receiveApproval(from, _value, address(this), _extraData); if (_gasPrice > 0) { gas = 35000 + gas.sub(gasleft()); require(_transfer(from, msg.sender, _gasPrice.mul(gas))); } emit SignatureRedeemed(_signature, from); return true; } /** *************************** Revoke PreSigned ************************** **/ /** * @dev Revoke signature without going through a delegate. * @param _sigToRevoke The signature that you no longer want to be used. **/ function revokeSignature(bytes _sigToRevoke) public returns (bool) { invalidSignatures[msg.sender][_sigToRevoke] = true; emit SignatureRedeemed(_sigToRevoke, msg.sender); return true; } /** * @dev Revoke signature through a delegate. * @param _signature The signature allowing this revocation. * @param _sigToRevoke The signature that you would like revoked. * @param _gasPrice The amount of token wei to be paid for each uint of gas. **/ function revokeSignaturePreSigned( bytes _signature, bytes _sigToRevoke, uint256 _gasPrice) public validPayload(356) returns (bool) { uint256 gas = gasleft(); address from = recoverRevokeHash(_signature, _sigToRevoke, _gasPrice); require(!invalidSignatures[from][_signature]); invalidSignatures[from][_signature] = true; invalidSignatures[from][_sigToRevoke] = true; if (_gasPrice > 0) { gas = 35000 + gas.sub(gasleft()); require(_transfer(from, msg.sender, _gasPrice.mul(gas))); } emit SignatureRedeemed(_signature, from); return true; } /** * @dev Get hash for a revocation. * @param _sigToRevoke The signature to be revoked. * @param _gasPrice The amount to be paid to delegate for sending this tx. **/ function getRevokeHash(bytes _sigToRevoke, uint256 _gasPrice) public pure returns (bytes32 txHash) { return keccak256(revokeSignatureSig, _sigToRevoke, _gasPrice); } /** * @dev Recover the address from a revocation signature. * @param _sigToRevoke The signature to be revoked. * @param _signature The signature allowing this revocation. * @param _gasPrice The amount of token wei to be paid for each unit of gas. **/ function recoverRevokeHash(bytes _signature, bytes _sigToRevoke, uint256 _gasPrice) public pure returns (address from) { return ecrecoverFromSig(getSignHash(getRevokeHash(_sigToRevoke, _gasPrice)), _signature); } /** ************************** PreSigned Constants ************************ **/ /** * @dev Used in frontend and contract to get hashed data of any given pre-signed transaction. * @param _to The address to transfer COIN to. * @param _value The amount of COIN to be transferred. * @param _extraData Extra data of tx if needed. Transfers and approves will leave this null. * @param _function Function signature of the pre-signed function being used. * @param _gasPrice The agreed-upon amount of COIN to be paid per unit of gas. * @param _nonce The user's nonce of the new transaction. **/ function getPreSignedHash( bytes4 _function, address _to, uint256 _value, bytes _extraData, uint256 _gasPrice, uint256 _nonce) public view returns (bytes32 txHash) { return keccak256(address(this), _function, _to, _value, _extraData, _gasPrice, _nonce); } /** * @dev Recover an address from a signed pre-signed hash. * @param _sig The signed hash. * @param _function The function signature for function being called. * @param _to The address to transfer/approve/transferFrom/etc. tokens to. * @param _value The amont of tokens to transfer/approve/etc. * @param _extraData The extra data included in the transaction, if any. * @param _gasPrice The amount of token wei to be paid to the delegate for each unit of gas. * @param _nonce The user's nonce for this transaction. **/ function recoverPreSigned( bytes _sig, bytes4 _function, address _to, uint256 _value, bytes _extraData, uint256 _gasPrice, uint256 _nonce) public view returns (address recovered) { return ecrecoverFromSig(getSignHash(getPreSignedHash(_function, _to, _value, _extraData, _gasPrice, _nonce)), _sig); } /** * @dev Add signature prefix to hash for recovery à la ERC191. * @param _hash The hashed transaction to add signature prefix to. **/ function getSignHash(bytes32 _hash) public pure returns (bytes32 signHash) { return keccak256("\x19Ethereum Signed Message:\n32", _hash); } /** * @dev Helps to reduce stack depth problems for delegations. Thank you to Bokky for this! * @param hash The hash of signed data for the transaction. * @param sig Contains r, s, and v for recovery of address from the hash. **/ function ecrecoverFromSig(bytes32 hash, bytes sig) public pure returns (address recoveredAddress) { bytes32 r; bytes32 s; uint8 v; if (sig.length != 65) return address(0); assembly { r := mload(add(sig, 32)) s := mload(add(sig, 64)) // Here we are loading the last 32 bytes. We exploit the fact that 'mload' will pad with zeroes if we overread. // There is no 'mload8' to do this, but that would be nicer. v := byte(0, mload(add(sig, 96))) } // Albeit non-transactional signatures are not specified by the YP, one would expect it to match the YP range of [27, 28] // geth uses [0, 1] and some clients have followed. This might change, see https://github.com/ethereum/go-ethereum/issues/2053 /** * @notice This used to be if (v < 27) { v += 27 } but that allowed delegates to duplicate signatures. * Any delegate that accepts signatures must now ensure that v == 0. **/ v += 27; if (v != 27 && v != 28) return address(0); return ecrecover(hash, v, r, s); } /** * @dev Frontend queries to find the next nonce of the user so they can find the new nonce to send. * @param _owner Address that will be sending the COIN. **/ function getNonce(address _owner) external view returns (uint256 nonce) { return nonces[_owner]; } /** ****************************** Constants ******************************* **/ /** * @dev Return total supply of token. **/ function totalSupply() external view returns (uint256) { return _totalSupply; } /** * @dev Return balance of a certain address. * @param _owner The address whose balance we want to check. **/ function balanceOf(address _owner) external view returns (uint256) { return balances[_owner]; } /** * @dev Allowed amount for a user to spend of another's tokens. * @param _owner The owner of the tokens approved to spend. * @param _spender The address of the user allowed to spend the tokens. **/ function allowance(address _owner, address _spender) external view returns (uint256) { return allowed[_owner][_spender]; } /** ****************************** onlyOwner ******************************* **/ /** * @dev Allow the owner to take ERC20 tokens off of this contract if they are accidentally sent. **/ function token_escape(address _tokenContract) external onlyOwner { CoinvestToken lostToken = CoinvestToken(_tokenContract); uint256 stuckTokens = lostToken.balanceOf(address(this)); lostToken.transfer(owner, stuckTokens); } /** * @dev Owner may set the standard sig to redirect to one of our pre-signed functions. * @dev Added in order to prepare for the ERC865 standard function names to be different from ours. * @param _standardSig The function signature of the finalized standard function. * @param _ourSig The function signature of our implemented function. **/ function updateStandard(bytes4 _standardSig, bytes4 _ourSig) external onlyOwner returns (bool success) { // These 6 are the signatures of our pre-signed functions. Don't want the owner messin' around. require(_ourSig == 0x1296830d || _ourSig == 0x617b390b || _ourSig == 0xadb8249e || _ourSig == 0x8be52783 || _ourSig == 0xc8d4b389 || _ourSig == 0xe391a7c4); standardSigs[_standardSig] = _ourSig; return true; } /** ***************************** Modifiers ******************************** **/ modifier validPayload(uint _size) { uint payload_size; assembly { payload_size := calldatasize } require(payload_size >= _size); _; } }