상세 컨텐츠

본문 제목

[Solidity] call, delegateCall

Dapp/Solidity

by 빠기윤 2019. 6. 18. 23:37

본문

모든 call들은 특정 주소의 다른 컨트랙트를 데이터, 가스, 이더와 함께 특정 함수를 호출합니다.

어떤 호출이냐에 따라 msg.sender나 변동 storage가 바뀌므로 기본 방식을 이해하고 사용하심이 바람직합니다.

 

call

컨트랙트 A를 통해 컨트랙트 B의 함수 호출시 B의 Storage를 변경시키며 msg.sender(호출자)는 컨트랙트A의 주소가 됩니다.

 

delegate call

컨트랙트 A를 통해 컨트랙트 B 호출시 B의 Storage를 변경시키지 않고, B의 코드를 A에서 실행합니다.

msg.sender와 msg.value가 컨트랙트 A 호출시와 같고, 변동되지 않습니다.

 

static call

상태를 변경하거나 읽는 경우를 구분하기 위해서 사용되며 다른 컨트랙트로 리다이렉트 되는 경우에도 상태변경이 일어나지 않음을 보장합니다.

 

callcode

v0.5.0이후 삭제되었습니다.

 

 

쉬운 이해를 위해서 직접 만들었던 이미지입니다. 중간에 가려진부분은 callcode로 0.5.0버전 이후 삭제되었습니다.

* A와 B 내의 코드는 쉬운 이해를 위해 간략히 생략하여 작성하여 그대로 사용하실경우 동작하지않습니다.

 

 


call을 할 시 매개변수로 호출하고자 하는 함수의 시그니처가 포함되어야합니다.

함수 시그니처는 String타입의 함수명+매개변수 형태를 sha3(keccak256) 해시의 앞 8바이트를 의미합니다.

 

0.5.0 버전 이전엔 call의 리턴값이 호출의 성공여부인 bool 뿐이었지만,

0.5.0 버전 이후엔 호출의 성공여부와 해당 함수의 리턴값을 bytes로 반환받을 수 있게 되었습니다.

 

  • sol version 0.5.0 이전

bool check = address.call(bytes4(keccak256("함수명(변수타입)")),매개변수값);

bool check = address.delegatecall(bytes4(keccak256("함수명(변수타입)")),매개변수값);

 

  • sol version 0.5.0 이후
(bool check, bytes memory data) = address.call(abi.encodeWithSignature("함수명(변수타입)",매개변수값));
(bool check, bytes memory data) = address.delegatecall(abi.encodeWithSignature("함수명(변수타입)",매개변수값));

//data decode
(uint a, uint b) = abi.decode(data, (uint, uint))

* abi.encodeWithSignature 로 변경된 이유는 keccak256()이 단일 바이트 인수만 허용하게 변경되었기 때문입니다.

 


 

 예제 

ERC20.sol (open-zeppelin)

function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
	_transfer(sender, recipient, amount);
	_approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
	return true;
}
...

 

MyContract.sol

(bool check, bytes memory data) = address(0xd26114cd6EE289AccF82350c8d8487fedB8A0C07).call(abi.encodeWithSignature("transferFrom(address,address,uint256)",0x4E9ce36E442e55EcD9025B9a6E0D88485d628A67,0xaA6C6E60D77674AD15aF8cbD9a9c406D5c83d8ca,100000 ether));

(bool returnBool) = abi.decode(data, (bool))

호출한 컨트랙트는 OMG (ERC20) 주소이며, transferFrom의 규약에 맞는 기능은 위(ERC20.sol)와 같습니다.

MyContract의 call로써

MyContract에게 0x4E9ce36E442e55EcD9025B9a6E0D88485d628A67 주소의 보유 OMG 토큰을 1개 전송가능한 권한이 있는 경우 0xaA6C6E60D77674AD15aF8cbD9a9c406D5c83d8ca에게 OMG 1개 전송이 revert 발생없이 정상작동합니다.

 

관련글 더보기

댓글 영역