# StargateComposer.sol

### swap()

This code snippet shows how the `StargateComposer.sol` uses the [`IStargateRouter`](https://stargateprotocol.gitbook.io/stargate/interfaces/evm-solidity-interfaces/istargaterouter.sol) to swap tokens using Stargate to another chain.

```solidity
/**
 * @param _dstChainId - destination chain identifier
 * @param _srcPoolId - source pool identifier
 * @param _dstPoolId - destination pool identifier
 * @param _refundAddress - refund address
 * @param _amountLD - amount (local decimals) to swap on source
 * @param _minAmountLD - min amount (local decimals) to receive on destination
 * @param _lzTxParams - struct: dstGasForCall,dstNativeAmount,dstNativeAddr
 * @param _to - destination address (the sgReceive() implementer)
 * @param _payload - bytes payload
 */
function swap(
    uint16 _dstChainId,
    uint256 _srcPoolId,
    uint256 _dstPoolId,
    address payable _refundAddress,
    uint256 _amountLD,
    uint256 _minAmountLD,
    IStargateRouter.lzTxObj memory _lzTxParams,
    bytes calldata _to,
    bytes calldata _payload
) external override payable nonSwapReentrant {
    bytes memory newPayload;
    bytes memory peer;
    if(_payload.length > 0) {
        newPayload = _buildPayload(_to, _payload);
        peer = _getPeer(_dstChainId);

        // overhead for calling composer's sgReceive()
        _lzTxParams.dstGasForCall += dstGasReserve + transferOverhead;
    } else {
        newPayload = "";
        peer = _to;
    }

    if(isEthPool(_srcPoolId)) {
        require(msg.value > _amountLD, "Stargate: msg.value must be > _swapAmount.amountLD");
        IStargateEthVault(stargateEthVaults[_srcPoolId]).deposit{value: _amountLD}();
        IStargateEthVault(stargateEthVaults[_srcPoolId]).approve(address(stargateRouter), _amountLD);
    } else {
        PoolInfo memory poolInfo = _getPoolInfo(_srcPoolId);
        // remove dust
        if (poolInfo.convertRate > 1) _amountLD = _amountLD.div(poolInfo.convertRate).mul(poolInfo.convertRate);
        // transfer token to this contract
        IERC20(poolInfo.token).safeTransferFrom(msg.sender, address(this), _amountLD);
    }

    stargateRouter.swap{value: isEthPool(_srcPoolId) ? msg.value - _amountLD : msg.value}(
        _dstChainId,
        _srcPoolId,
        _dstPoolId,
        _refundAddress,
        _amountLD,
        _minAmountLD,
        _lzTxParams,
        peer, // swap the to address with the peer address
        newPayload
    );
}
```

### buildPayload()

In the swap function it calls buildPayload to include the msg.sender in the payload.

```solidity
 function _buildPayload(
    bytes calldata _to,
    bytes calldata _payload
) internal view returns (bytes memory) {
    require(_to.length == 20, "Stargate: invalid to address");

    // new payload = to(20) + sender(20) + payload
    // encoding the sender allows the receiver to know who called the Stargate
    return abi.encodePacked(_to, msg.sender, _payload);
}

```

### sgReceive()

`StargateComposer.sol` implements [IStargateReceiver](https://stargateprotocol.gitbook.io/stargate/interfaces/evm-solidity-interfaces/istargatereceiver.sol) so it can implement the `sgReceive` function and receive the tokens and payload from the `IStargateRouter` on the destination chain. It then forwards the `sgReceive` call to the intended receiver with the original msg.sender who initialed the swap on source.

```solidity
/**
 * @param _srcChainId - source chain identifier
 * @param _srcAddress - source address identifier
 * @param _nonce - message ordering nonce
 * @param _token - token contract
 * @param _amountLD - amount (local decimals) to recieve 
 * @param _payload - bytes containing the toAddress
 */
function sgReceive(
    uint16 _srcChainId,
    bytes memory _srcAddress,
    uint256 _nonce,
    address _token,
    uint256 _amountLD,
    bytes memory _payload
) external override {
    require(msg.sender == address(stargateRouter), "Stargate: only router");
    // will just ignore the payload in some invalid configuration
    if (_payload.length <= 40) return; // 20 + 20 + payload

    address intendedReceiver = _payload.toAddress(0);

    (bool success, bytes memory data) = _token.call(abi.encodeWithSelector(SELECTOR, intendedReceiver, _amountLD));
    if (success && (data.length == 0 || abi.decode(data, (bool)))) {
        if (!intendedReceiver.isContract()) return; // ignore

        bytes memory callData = abi.encodeWithSelector(
            IStargateReceiver.sgReceive.selector,
            _srcChainId,
            abi.encodePacked(_payload.toAddress(20)), // use the caller as the srcAddress (the msg.sender caller the StargateComposer at the source)
            _nonce,
            _token,
            _amountLD,
            _payload.slice(40, _payload.length - 40)
        );

        // no point in requires, because it will revert regardless
        uint256 externalGas = gasleft() - dstGasReserve;

        (bool safeCallSuccess, bytes memory reason) = intendedReceiver.safeCall(externalGas, 0, 150, callData); // only return 150 bytes of data

        if (!safeCallSuccess) {
            payloadHashes[_srcChainId][_srcAddress][_nonce] = keccak256(abi.encodePacked(intendedReceiver, callData));
            emit CachedSwapSaved(_srcChainId, _srcAddress, _nonce, reason);
        }

    } else {
        // do nothing, token swap failed and can't be delivered, tokens are held inside this contract
        emit ComposedTokenTransferFailed(_token, intendedReceiver, _amountLD);
    }
}
```
