Skip to main content

Transfer of Reserve Tokens

function depositReserveToken(
bool isSourceNative,
bytes calldata swapData,
bytes calldata executeData,
bytes calldata requestMetadata
) external payable;

Reserve tokens are the tokens that have been kept in reserve by the Voyager protocol. The Voyager keeps reserves of some selected tokens on each chain so that it is able to provide fund transfers by locking funds on source chain and unlocking the funds on the destination chain. These include some stable tokens, wrapped native tokens for that chain as well as other tokens according to the needs as well as partnerships of projects with the Voyager .

When a user wants to transfer any of these reserve tokens from source chain to any other token on the destination chain, this function is to be called. After this function is called, the Voyager’s infrastructure will handle the transfer of tokens to the other chain.

Parameters:

isSourceNativeIf the source token is the native token for that chain, this should be true.
swapDataabi encoded data for the required swap which is created by an API
executeDataabi encoded data for the execution on the destination chain which is created by an API
requestMetadataabi encoded data

The Swap Data includes:

  1. srcStableTokenAmount: Amount of the reserve token the user wants to transfer to the other chain.
  2. srcStableTokenAddress: Address of the reserve token the user wants to transfer to the other chain.
  3. srcTokenAddress: Address of the token the user wants to transfer to the other chain. This will be the same as srcStableTokenAddress in case of reserve tokens.
  4. destChainIdBytes: The Chain ID identifier for the destination chain.

The Execute Data includes:

  1. destTokenAmount: Amount of destination tokens user will receive. This will be checked in the middleware and if this amount (USD Value) is larger than what user deposited, the transaction will be reverted.
  2. destTokenAddress: Address of the token user will receive on the destination chain.
  3. isDestNative: If the token to be received on the destination chain is native token for that chain, this is set to 1 else 0.
  4. destStableTokenAddress: Address of the stable token in which USD value for the tokens to be received will be calculated on the middleware.
  5. recipient: Address of the recipient on the destination chain.
  6. dataTx: Data for the transaction for swap on destination chain received from the API. If the token to be received on the destination chain is a reserve token or an LP token for that chain, the dataTx will be an empty bytes array.
  7. path: Path for the swap on destination chain received from the API. If the token to be received on the destination chain is a reserve token or an LP token for that chain, the path will be an empty address array.
  8. flags: The identifiers of DEXes that will be used for swap on destination chain received from the API. If the token to be received on the destination chain is a reserve token or an LP token for that chain, the flags will be an empty uint256 array.
  9. widgetID: Widget ID of the partner who has integrated the Voyager Widget. If you are not a partner, you can pass uint256 0 as widgetID.
info

Swap data and Execute data will directly be generated by the API. You don’t need to worry about generating this data.

The Request Metadata includes:

  1. destGasLimit: Gas limit required for execution of the request on the destination chain. This can be calculated using tools like hardhat-gas-reporter.

  2. destGasPrice: Gas price of the destination chain. This can be calculated using the RPC of destination chain.

// using ethers.js
const gasPrice = await provider.getGasPrice();

// using web3.js
const gasPrice = web3.eth.getGasPrice().then((result) => {
console.log(web3.utils.fromWei(result, 'ether'));
});

To avoid the need for calculation, it can be passed as 0. The Router chain will then estimate the real-time gas price for them.

  1. ackGasLimit: Gas limit required for the execution of the acknowledgment on the source chain. This can be calculated using tools like hardhat-gas-reporter.

  2. ackGasPrice: Gas price of the source chain. This can be calculated using the RPC of source chain as shown in the above snippet. To avoid the need for calculation, it can be passed as 0. The Router chain will then estimate the real-time gas price for them.

  3. relayerFees: This parameter functions similarly to the priority fees on other blockchain networks. Since the Router chain relayers handle the execution of cross-chain requests on the destination chain, setting a higher relayerFees will increase the likelihood of your request being prioritized by relayers. If a very low relayerFees is provided, the Router chain will automatically adjust it to the minimum required amount to ensure that it is executed. If it is passed as 0, the Router chain will default it to the minimum set Relayer fee value.

  4. ackType: When the contract calls have been executed on the destination chain, the destination chain Gateway contract sends an acknowledgent back to the Router chain. iDapps have the option to get this acknowledgment from the Router chain to the source chain and execute some operations based on the ack.

  • If ackType = 0, the user doesn't want the acknowledgment to be forwarded back to the source chain.
  • If ackType = 1, the acknowledgment is expected to be received only if the calls were successfully executed on the destination chain, and the user intends to perform some operation on the source chain after receiving the ack.
  • If ackType = 2, an acknowledgment is needed only in case of an error occurring on the destination chain. This options also allows for execution of certain operations after receiving the ack.
  • If ackType = 3, an acknowledgment is needed from the destination chain regardless of whether the call succeeds or fails, and some operations need to be performed based on the ack.
  1. isReadCall: Router provides dApps an option to query a contract on another chain and receive the data back on the source chain as an acknowledgment. If the intention is only to query a contract on the destination chain and not perform any write operation there, then set this option to true.

  2. asmAddress: As part of Router's modular security framework, developers can integrate an ASM module to add an extra layer of security on top of the infra-level security provided by the Router Chain. These modules will be in the form of smart contracts on the destination chain, and their addresses should be passed as bytes in this variable. Documentation for ASM can be found here.

It can be achieved by adding the following function in your contract:

function getRequestMetadata(
uint64 destGasLimit,
uint64 destGasPrice,
uint64 ackGasLimit,
uint64 ackGasPrice,
uint128 relayerFees,
uint8 ackType,
bool isReadCall,
bytes memory asmAddress
) public pure returns (bytes memory) {
bytes memory requestMetadata = abi.encodePacked(
destGasLimit,
destGasPrice,
ackGasLimit,
ackGasPrice,
relayerFees,
ackType,
isReadCall,
asmAddress
);
return requestMetadata;
}

Alternatively, the requestMetadata parameter can be created in TypeScript or JavaScript using the following function:

function getRequestMetadata(
destGasLimit: number,
destGasPrice: number,
ackGasLimit: number,
ackGasPrice: number,
relayerFees: string,
ackType: number,
isReadCall: boolean,
asmAddress: string
): string {
return ethers.utils.solidityPack(
[
'uint64',
'uint64',
'uint64',
'uint64',
'uint128',
'uint8',
'bool',
'string',
],
[
destGasLimit,
destGasPrice,
ackGasLimit,
ackGasPrice,
relayerFees,
ackType,
isReadCall,
asmAddress,
]
);
}