Skip to main content

🔁 Return Data Proxy

Introduction​

The Return Data Proxy library provides functions for calling other contracts and handling their return data efficiently.

Implementation​

The ReturnDataProxy library employs assembly to directly place data into returndata. This technique optimizes gas usage by reducing encoding and decoding overhead. It's crucial to ensure that calls to this library occur at the end of the function, as instructions following this call won't be executed.

Functions​

To use the ReturnDataProxy library, you need to import it.

import "@solarity/solidity-lib/libs/utils/ReturnDataProxy.sol";

And optionally bind it to the type with the using statement.

using ReturnDataProxy for address;

yield​

function yield(address target_, bytes memory calldata_) internal;
function yield(address target_, uint256 value_, bytes memory calldata_) internal;

Description​

This function is used to call a function of target_ with a calldata_ and an option to transfer value_. Should be used as the last call of the function as it terminates the current context.

Time complexity​

Constant.

Example​

struct Entry {
bytes data;
string name;
uint256 value;
}

contract Target {
Entry public entry;

function getEntry() external returns (Entry memory) {
++entry.value;

return entry;
}
}

contract Proxy {
function callGetEntry(
address target_
) external returns (Entry memory) {
target_.yield(abi.encodeWithSelector(Target.getEntry.selector));

// Automatically substitutes return statement
// Instructions here won't be executed
}
}

Target target_ = new Target();
Proxy proxy_ = new Proxy();

// returns entry from target storage, possibly changes target state
proxy.delegateCallGetEntry(address(target));

delegateYield​

function delegateYield(address target_, bytes memory calldata_) internal;

Description​

This function is used to delegatecall a function of target_ with a calldata_. Should be used as the last call of the function as it terminates the current context.

Time complexity​

Constant.

Example​

struct Entry {
bytes data;
string name;
uint256 value;
}

contract Target {
Entry public entry;

function getEntry() external returns (Entry memory) {
++entry.value;

return entry;
}
}

contract Proxy {
function delegateCallGetEntry(
address target_
) external returns (Entry memory) {
target_.delegateYield(abi.encodeWithSelector(Target.getEntry.selector));

// Automatically substitutes return statement
// Instructions here won't be executed
}
}

Target target_ = new Target();
Proxy proxy_ = new Proxy();

// returns entry from proxy storage, possibly changes proxy state
proxy.delegateCallGetEntry(address(target));

staticYield​

function staticYield(address target_, bytes memory calldata_) internal view;

Description​

This function is used to staticcall a function of target_ with a calldata_. Should be used as the last call of the function as it terminates the current context.

Time complexity​

Constant.

Example​

struct Entry {
bytes data;
string name;
uint256 value;
}

contract Target {
Entry public entry;

function getEntry() external view returns (Entry memory) {
return entry;
}
}

contract Proxy {
function delegateCallGetEntry(
address target_
) external view returns (Entry memory) {
target_.delegateYield(abi.encodeWithSelector(Target.getEntry.selector));

// Automatically substitutes return statement
// Instructions here won't be executed
}
}

Target target_ = new Target();
Proxy proxy_ = new Proxy();

// returns entry from target memory, does not change target state
proxy.delegateCallGetEntry(address(target));