intente llamar al token erc20 transferFrom()
usando el ensamblaje (para ahorrar algo de gasolina), codifique como este:
pragma solidity ^0.4.24;
contract TestAssemblyAndRevert {
function test(address from, address to, uint256 value) public {
// a standard erc20 token
address token = 0xedc2d4aca4f9b6a23904fbb0e513ea0668737643;
// call transferFrom() of token using assembly
assembly { // LineA
// keccak256('transferFrom(address,address,uint256)') & 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
// calldatacopy(t, f, s) copy s bytes from calldata at position f to mem at position t
// copy from, to, value from calldata to memory
calldatacopy(4, 4, 96)
// call ERC20 Token contract transferFrom function
let result := call(gas, token, 0, 0, 100, 0, 32)
if eq(result, 1) {
return(0, 0)
}
//revert(0, 0); // LineB
}
revert("TOKEN_TRANSFER_FROM_ERROR"); // LineC
}
}
el token es un token ERC20 estándar que cuando algún gastador intenta llamar transferFrom()
sin suficiente asignación, revertirá, en nuestro caso, esta línea:
let result := call(gas, token, 0, 0, 100, 0, 32)
result
será 0.
Lo que me sorprende es que cuando esto sucede, la transacción consumirá todo el gasLimit. ¿porqué es eso?
Probé varios otros casos, ninguno de ellos consumirá el gas:
revert("TOKEN_TRANSFER_FROM_ERROR")
, LineCResultó que es causado por estropear la memoria, si usamos el puntero de memoria libre: let ptr := mload(0x40)
, el problema de quemar todo el gas desaparecerá.
pragma solidity ^0.4.24;
contract TestAssemblyAndRevert {
function test(address from, address to, uint256 value) public {
// a standard erc20 token
address token = 0xedc2d4aca4f9b6a23904fbb0e513ea0668737643;
// call transferFrom() of token using assembly
assembly {
let ptr := mload(0x40)
// keccak256('transferFrom(address,address,uint256)') & 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
mstore(ptr, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
// calldatacopy(t, f, s) copy s bytes from calldata at position f to mem at position t
// copy from, to, value from calldata to memory
calldatacopy(add(ptr, 4), 4, 96)
// call ERC20 Token contract transferFrom function
let result := call(gas, token, 0, ptr, 100, ptr, 32)
if eq(result, 1) {
return(0, 0)
}
}
revert("TOKEN_TRANSFER_FROM_ERROR");
}
}