Quiero saber cómo instanciar un contrato existente implementado en la cadena de bloques usando su dirección. p.ej:
contract A {
function f1()
{}
}
A
se implementa en la cadena de bloques y, por contrato B
, quiero llamar a la función f1()
y obtener su devolución. p.ej:
contract B {
address contrac_A=0x123456;
//call f1 from A
}
¿Cómo debo llamarlo usando la dirección de A
?
Si el contrato implementado no se adhiere a la ABI, pero conoce la firma del contrato (tipos de nombre y argumento), podría usar:
contract_address.call(bytes4(sha3("function_name(types)")),parameters_values)
por ejemplo: contrac_A.call(bytes4(sha3("f()"))
si bien no hay entrada, no hay parámetros en su ejemplo.
reemplace contract_address,function_name,parameters_values por sus credenciales.
Editar: como sha3 ha quedado obsoleto, es mejor usar keccak256 en su lugar de la siguiente manera:bytes4(keccak256("f()")).
Además, desde solidity 0.4.22, las funciones globales abi.encode(), abi.encodePacked(), abi.encodeWithSelector() and abi.encodeWithSignature()
se han definido para codificar datos estructurados y, por lo tanto, nos ayudan a crear llamadas válidas (devuelven los 4 bytes necesarios) de la siguiente manera:
contract_address.call.value(1 ether).gas(10)(abi.encodeWithSignature("register(string)", "MyName"));
Documentación :
https://github.com/ethereum/wiki/wiki/Solidity-Features#generic-call-method
https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector
Más aclaraciones a la respuesta de @Edmund:
contract A { // This doesn't have to match the real contract name. Call it what you like.
function f1(bool arg1, uint arg2) returns(uint); // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}
contract YourContract {
function doYourThing(address addressOfA) returns(uint) {
A my_a = A(addressOfA);
return my_a.f1(true, 3);
}
}
Esto muestra el uso del valor de retorno de f1
.
Además, si f1
encuentra una excepción (imagine que su implementación es function f1(bool arg1, uint arg2) returns(uint) { throw; }
), la excepción se propaga y my_a.f1
también throw
revertirá una transacción que invocó doYourThing
.
En la práctica, tendrás 3 archivos.
AbstractA.sol contiene:
contract A {
function f1(bool arg1, uint arg2) returns(uint); // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}
YourContract.sol contiene:
import "AbstractA.sol"
contract YourContract {
function doYourThing(address addressOfA) returns(uint) {
A my_a = A(addressOfA);
return my_a.f1(true, 3);
}
}
A.sol contiene:
contract A {
// implementation of f1
function f1(bool arg1, uint arg2) returns(uint) {
if (arg1) {
throw;
} else {
return arg2;
}
}
}
call
call
se sugiere en la respuesta de @Badr, pero debe usarse con mucho cuidado. Los documentos de Solidity afirman:
Las tres funciones son funciones
call
de muy bajo niveldelegatecall
ycallcode
solo deben usarse como último recurso, ya que rompen la seguridad de tipos de Solidity.
Además, el valor de retorno de f1
no se puede obtener usando call
like addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3)
porque call
solo devuelve un bool
( false
si la llamada encuentra una excepción).
Esto significa que la excepción debe propagarse manualmente como:
if (!addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3)) {
throw;
}
contract A { // This doesn't have to match the real contract name. Call it what you like.
function f1(){} // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}
contract YourContract
function doYourThing() {
A my_a = A(contract_A);
my_a.f1();
}
}
Aquí hay un código de Solidity para el nuevo contrato que puede llamar a la función f1() desde su antiguo contrato . Espero que esto ayude. Traté de mantenerlo lo más simple posible.
import "./Old.sol"; // You import the existing contract.
/**
* The NEW contract will call the Old one
*/
contract New {
Old OLD; // Intitilize old contract variable (empty)
/**
* Set the address for Old contract (We call this function and enter the address of the OLD contract)
*/
function setOldContractAddress(address addr) public {
OLD = Old(addr);
}
/**
* Function that allows us to call f1() from the Old contract
*/
function callOLDcontract() public {
OLD.f1();
}
}
crissi mariam robert
Badr Bellaj