Add Greg's documentation to MixinErc20Transfer

This commit is contained in:
Remco Bloemen 2018-06-23 18:03:49 +02:00 committed by Amir Bandeali
parent b8051c8fed
commit 562fec01d8

View File

@ -44,38 +44,60 @@ contract MixinERC20Transfer is
// Decode asset data. // Decode asset data.
address token = assetData.readAddress(16); address token = assetData.readAddress(16);
// Transfer tokens.
// We do a raw call so we can check the success separate
// from the return data.
// We construct calldata for the `token.transferFrom` ABI.
// The layout of this calldata is in the table below.
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 3 * 32 | function parameters: |
// | | 4 | | 1. from |
// | | 36 | | 2. to |
// | | 68 | | 3. amount |
bytes4 transferFromSelector = IERC20Token(token).transferFrom.selector; bytes4 transferFromSelector = IERC20Token(token).transferFrom.selector;
bool success; bool success;
assembly { assembly {
/////// Setup State /////// /////// Setup State ///////
// `cdStart` is the start of the calldata for `token.transferFrom` (equal to free memory ptr). // `cdStart` is the start of the calldata for `token.transferFrom` (equal to free memory ptr).
let cdStart := mload(64) let cdStart := mload(64)
// `cdEnd` is the end of the calldata for `token.transferFrom`.
let cdEnd := add(cdStart, 100)
/////// Setup Header Area /////// /////// Setup Header Area ///////
// This area holds the 4-byte `transferFromSelector`. // This area holds the 4-byte `transferFromSelector`.
// Any trailing data in transferFromSelector will be
// overwritten in the next `mstore` call.
mstore(cdStart, transferFromSelector) mstore(cdStart, transferFromSelector)
/////// Setup Params Area /////// /////// Setup Params Area ///////
// Each parameter is padded to 32-bytes. The entire Params Area is 96 bytes. // Each parameter is padded to 32-bytes.
// A 20-byte mask is applied to addresses to zero-out the unused bytes. // The entire Params Area is 96 bytes.
// A 20-byte mask is applied to addresses to
// zero-out the unused bytes.
mstore(add(cdStart, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) mstore(add(cdStart, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(cdStart, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) mstore(add(cdStart, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(cdStart, 68), amount) mstore(add(cdStart, 68), amount)
/////// Call `token.transferFrom` using the constructed calldata /////// /////// Call `token.transferFrom` using the calldata ///////
success := call( success := call(
gas, gas, // forward all gas
token, token, // call address of token contract
0, 0, // don't send any ETH
cdStart, cdStart, // pointer to start of input
sub(cdEnd, cdStart), 100, // length of input
cdStart, cdStart, // write output over input
32 32 // output size should be 32 bytes
) )
// The transfer succeeded if the call succeeded and either /////// Check return data. ///////
// If there is no return data, we assume the token incorrectly
// does not return a bool. In this case we expect it to revert
// on failure, which was handled above.
// If the token does return data, we require that it is a single
// nonzero 32 bytes value.
// So the transfer succeeded if the call succeeded and either
// returned nothing, or returned a non-zero 32 byte value. // returned nothing, or returned a non-zero 32 byte value.
success := and(success, or( success := and(success, or(
iszero(returndatasize), iszero(returndatasize),