Я хочу знать, как создать экземпляр существующего контракта, развернутого в блокчейне, используя его адрес. например:
contract A {
function f1()
{}
}
A
развернут в блокчейне, и в контракте B
я хочу вызвать функцию f1()
и получить ее результат. например:
contract B {
address contrac_A=0x123456;
//call f1 from A
}
Как я должен назвать это, используя адрес A
?
Если развернутый контракт не соответствует ABI, но вы знаете подпись контракта (имя и типы аргументов), вы можете использовать:
contract_address.call(bytes4(sha3("function_name(types)")),parameters_values)
например: contrac_A.call(bytes4(sha3("f()"))
пока в вашем примере нет входных параметров.
замените адрес_контракта, имя_функции, значения_параметров своими учетными данными.
Редактировать: поскольку sha3 устарел, лучше использовать вместо него keccak256 следующим образом:bytes4(keccak256("f()")).
Кроме того, начиная с Solidity 0.4.22, глобальные функции abi.encode(), abi.encodePacked(), abi.encodeWithSelector() and abi.encodeWithSignature()
были определены для кодирования структурированных данных и, следовательно, помогают нам построить правильный вызов (они возвращают необходимые 4 байта) следующим образом:
contract_address.call.value(1 ether).gas(10)(abi.encodeWithSignature("register(string)", "MyName"));
Документация :
https://github.com/ethereum/wiki/wiki/Solidity-Features#общий-вызов-метод
https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#селектор функций
Дополнительные разъяснения к ответу @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);
}
}
Это показывает использование возвращаемого значения из f1
.
Кроме того, если f1
встречается исключение (представьте, что его реализация — function f1(bool arg1, uint arg2) returns(uint) { throw; }
), исключение распространяется, а my_a.f1
также throw
отменяет транзакцию, вызвавшую doYourThing
.
На практике у вас будет 3 файла.
AbstractA.sol содержит:
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 содержит:
import "AbstractA.sol"
contract YourContract {
function doYourThing(address addressOfA) returns(uint) {
A my_a = A(addressOfA);
return my_a.f1(true, 3);
}
}
A.sol содержит:
contract A {
// implementation of f1
function f1(bool arg1, uint arg2) returns(uint) {
if (arg1) {
throw;
} else {
return arg2;
}
}
}
call
call
предлагается в ответе @Badr, но его следует использовать очень осторожно. Документы Solidity гласят :
Все три функции
call
и являются функциями очень низкого уровняdelegatecall
иcallcode
должны использоваться только в крайнем случае, поскольку они нарушают безопасность типов Solidity.
Кроме того, возвращаемое значение f1
не может быть получено с помощью функции call
like, addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3)
поскольку call
возвращает a bool
( только в false
том случае, если вызов встречает исключение).
Это означает, что исключение должно распространяться вручную, например:
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();
}
}
Вот код Solidity для Нового контракта , который может вызывать функцию f1() из вашего Старого контракта . Надеюсь это поможет. Я старался сделать это как можно проще.
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();
}
}
Крисси Мариам Роберт
Бадр Беллай