Composability: StargateComposed.sol
Leverage Stargate to perform additional smart contract logic on the destination chain!
To test Stargate Composability you can mint yourself testnet tokens using the addresses found on the Test Faucet page.
This contract is an example of the power of composability. A contract on the source chain composes an AMM and Stargate, and a destination contract which has access to an AMM implements
sgReceive()
receives the tokens and a payload to perform additional logic.The StargateComposed.sol contract can swap native on the source chain for native on the destination chain. To swap tokens to another chain using Stargate this contract must use the IStargateRouter.sol to interact with Stargate. This code snippet shows how the contract uses it to swap native on the source chain for native on the destination chain.
Warning: When composing, Do Not swap() real funds to a contract address that does not implement sgReceive() or your *will* lose those funds.
/// @param dstChainId The message ordering nonce
/// @param bridgeToken The remote Bridge address
/// @param srcPoolId The token contract on the local chain
/// @param dstPoolId The qty of local _token contract tokens
/// @param nativeAmountIn The amount of native token coming in on source
/// @param to The address to send the destination tokens to
/// @param amountOutMin The minimum amount of stargatePoolId token to get out of amm router
/// @param amountOutMinSg The minimum amount of stargatePoolId token to get out on destination chain
/// @param amountOutMinDest The minimum amount of native token to receive on destination
/// @param deadline The overall deadline
/// @param destStargateComposed The destination contract address that must implement sgReceive()
function swapNativeForNative(
uint16 dstChainId,
address bridgeToken,
uint16 srcPoolId,
uint16 dstPoolId,
uint nativeAmountIn,
address to,
uint amountOutMin,
uint amountOutMinSg,
uint amountOutMinDest,
uint deadline,
address destStargateComposed
)
Using the amm router, swap native into the Stargate pool token, sending the output token to this contract.
// special token value that indicates the sgReceive() should swap OUT native asset
address public OUT_TO_NATIVE = 0x0000000000000000000000000000000000000000;
uint bridgeAmount;
// using the amm router, swap native into the Stargate pool token, sending the output token to this contract
{
// create path[] for amm swap
address[] memory path = new address[](2);
path[0] = IUniswapV2Router02(ammRouter).WETH(); // native IN requires that we specify the WETH in path[0]
path[1] = bridgeToken; // the bridge token,
uint[] memory amounts = IUniswapV2Router02(ammRouter).swapExactETHForTokens{value:nativeAmountIn}(
amountOutMin,
path,
address(this),
deadline
);
bridgeAmount = amounts[1];
require(bridgeAmount > 0, 'error: ammRouter gave us 0 tokens to swap() with stargate');
// this contract needs to approve the stargateRouter to spend its path[1] token!
IERC20(bridgeToken).approve(address(stargateRouter), bridgeAmount);
}
// encode payload data to send to destination contract, which it will handle with sgReceive()
bytes memory data;
{
data = abi.encode(OUT_TO_NATIVE, deadline, amountOutMinDest, to);
}
Call IStargateRouter swap() to send the tokens to the destination chain.
IStargateRouter(stargateRouter).swap{value:msg.value.sub(nativeAmountIn)}(
dstChainId, // the destination chain id
srcPoolId, // the source Stargate poolId
dstPoolId, // the destination Stargate poolId
payable(msg.sender), // refund adddress. if msg.sender pays too much gas, return extra eth
bridgeAmount, // total tokens to send to destination chain
amountOutMinSg, // minimum
IStargateRouter.lzTxObj(500000, 0, "0x"), // 500,000 for the sgReceive()
abi.encodePacked(destStargateComposed), // destination address, the sgReceive() implementer
data // bytes payload
);
StargateComposed.sol implements IStargateReceiver so it can implement the
sgReceive
function to receive the tokens and payload./// @param _chainId The remote chainId sending the tokens
/// @param _srcAddress The remote Bridge address
/// @param _nonce The message ordering nonce
/// @param _token The token contract on the local chain
/// @param amountLD The qty of local _token contract tokens
/// @param _payload The bytes containing the _tokenOut, _deadline, _amountOutMin, _toAddr
function sgReceive(
uint16 _chainId,
bytes memory _srcAddress,
uint _nonce,
address _token,
uint amountLD,
bytes memory payload
)
Unpack the payload to get
_tokenOut
,_deadline
,_amountOutMin
,_toAddr
. Approve the amm router so it can swap our tokens. Get the pre balance of the _toAddr
to emit an event of exact amount sent.(address _tokenOut, uint _deadline, uint _amountOutMin, address _toAddr) = abi.decode(payload, (address, uint, uint, address));
IERC20(_token).approve(address(ammRouter), amountLD);
uint _toBalancePreTransferOut = address(_toAddr).balance;
Use the amm router to swap the incoming bridge token into native token
if(_tokenOut == address(0x0)){
address[] memory path = new address[](2);
path[0] = _token;
path[1] = IUniswapV2Router02(ammRouter).WETH();
try IUniswapV2Router02(ammRouter).swapExactTokensForETH(
amountLD, // the stable received from stargate at the destination
_amountOutMin, // slippage param, min amount native token out
path, // path[0]: stabletoken address, path[1]: WETH from sushi router
_toAddr, // the address to send the *out* native to
_deadline // the unix timestamp deadline
) {
emit ReceivedOnDestination(
OUT_TO_NATIVE,
address(_toAddr).balance.sub(_toBalancePreTransferOut)
);
} catch {
IERC20(_token).transfer(_toAddr, amountLD);
emit ReceivedOnDestination(_token, amountLD);
}
}
Use the amm router to swap the incoming bridge token into an ERC20 token
else {
uint _toAddrTokenBalancePre = IERC20(_tokenOut).balanceOf(_toAddr);
address[] memory path = new address[](2);
path[0] = _token;
path[1] = _tokenOut;
try IUniswapV2Router02(ammRouter).swapExactTokensForTokens(
amountLD, // the stable received from stargate at the destination
_amountOutMin, // slippage param, min amount native token out
path, // path[0]: stabletoken address, path[1]: WETH from sushi router
_toAddr, // the address to send the *out* tokens to
_deadline // the unix timestamp deadline
) {
emit ReceivedOnDestination(_tokenOut, IERC20(_tokenOut).balanceOf(_toAddr).sub(_toAddrTokenBalancePre));
} catch {
IERC20(_token).transfer(_toAddr, amountLD);
emit ReceivedOnDestination(_token, amountLD);
}
}
Last modified 1yr ago