From 46deee66836b8f3a6175c12946aec31b771fce09 Mon Sep 17 00:00:00 2001 From: Sarp Date: Thu, 15 Aug 2024 20:34:33 +0300 Subject: [PATCH 1/5] Add ICTT send-and-call course --- .../12-send-and-call/01-intro.mdx | 22 +++ .../12-send-and-call/02-prerequisites.mdx | 14 ++ .../03-send-and-call-receivers.mdx | 39 +++++ .../04-wrap-exchange-contract.mdx | 165 ++++++++++++++++++ .../05-deploy-wrapped-exchange-contract.mdx | 23 +++ .../12-send-and-call/06-deployment.mdx | 13 ++ .../07-test-cross-chain-swap.mdx | 39 +++++ .../12-send-and-call/send-and-call.mdx | 9 - .../interchain-token-transfer/meta.json | 4 +- .../cross-chain-swap-tx-receipt.png | Bin 0 -> 123751 bytes 10 files changed, 318 insertions(+), 10 deletions(-) create mode 100644 content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/04-wrap-exchange-contract.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/05-deploy-wrapped-exchange-contract.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/06-deployment.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/07-test-cross-chain-swap.mdx delete mode 100644 content/course/interchain-token-transfer/12-send-and-call/send-and-call.mdx create mode 100644 public/course-images/interchain-token-transfer/cross-chain-swap-tx-receipt.png diff --git a/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx b/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx new file mode 100644 index 00000000..37e34e4d --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx @@ -0,0 +1,22 @@ +--- +title: Introduction +description: Learn how to call another contract function after send tokens to another L1s. +updated: 2024-08-15 +authors: [0xstt] +icon: Book +--- + +In addition to supporting basic token transfers, the token bridge contracts offer a `sendAndCall` interface for bridging tokens and using them in a smart contract interaction all within a single Interchain Messaging message. If the call to the recipient smart contract fails, the bridged tokens are sent to a fallback recipient address on the destination chain of the transfer. The `sendAndCall` interface enables the direct use of bridged tokens in dApps on other chains, such as performing swaps, using the tokens to pay for fees when invoking services, etc. + +Teleporter Messenger has the ability to receive cross-chain messages on the destination chain and casts related messages to the `TeleporterMessage` struct. It then sends these messages to the Home/Remote Bridge contract, and handles them as `SEND` or `CALL`, as implemented in `TokenHome.sol` or `TokenRemote.sol`. + +In this section we will cover the usage of the `CALL` message type with an example implementation. + +When `sendAndCall` function is triggered, the following actions are taken; + +- The Bridge Contract grants an allowance to spend tokens on the destination contract. +- The Bridge Contract encodes the received message as parameters for the `receiveToken` function, as defined in the `IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` interface. +- The Bridge Contract checks whether the destination contract's function execution is successfull. +- The Bridge Contract retrieves the remaining allowance to check if there are any unspent tokens exists. +- The Bridge Contract removes the allowance for the destination contract. +- The Bridge Contract sends the remaining tokens to the fallback recipient. If the destination contract fails to execute the function, the full amount will be sent to the fallback recipient. \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx b/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx new file mode 100644 index 00000000..07af4c82 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx @@ -0,0 +1,14 @@ +--- +title: Prerequisites +description: Here is what you need before starting this chapter. +updated: 2024-08-15 +authors: [0xstt] +icon: Book +--- + +The following prerequisites were covered im previous sections, so you should have already deployed the following contracts before starting this chapter: + +- Base ERC20 Token on L1 +- Home Bridge Contract on L1 +- Remote Bridge Contract on Fuji +- A Running AWM-relayer from your L1 to Fuji diff --git a/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx b/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx new file mode 100644 index 00000000..2e3c1663 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx @@ -0,0 +1,39 @@ +--- +title: Send and Call Receivers +description: Learn how tokens are received by the receivers. +updated: 2024-08-15 +authors: [0xstt] +icon: BookOpen +--- + +`IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` are used for contracts that handle receiving ERC20 or native tokens. + +Mock implementations are already available in the [Avalanche Interchain Token Transfer](https://github.com/ava-labs/avalanche-interchain-token-transfer) repository. + +What we are going to do is; simply deploy a new contract that implements the `IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` interfaces that has a capability to use received tokens. + +```bash +/** + * @notice Interface for contracts that are called to receive token transfers. + */ +interface IERC20SendAndCallReceiver { + /** + * @notice Called to receive the amount of the given token + * @param sourceBlockchainID Blockchain ID that the transfer originated from + * @param originTokenTransferrerAddress Address of the token transferrer that initiated the Teleporter message + * @param originSenderAddress Address of the sender that sent the transfer. This value + * should only be trusted if {originTokenTransferrerAddress} is verified and known. + * @param token Address of the token to be received + * @param amount Amount of the token to be received + * @param payload Arbitrary data provided by the caller + */ + function receiveTokens( + bytes32 sourceBlockchainID, + address originTokenTransferrerAddress, + address originSenderAddress, + address token, + uint256 amount, + bytes calldata payload + ) external; +} +``` \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/04-wrap-exchange-contract.mdx b/content/course/interchain-token-transfer/12-send-and-call/04-wrap-exchange-contract.mdx new file mode 100644 index 00000000..fc2a08f5 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/04-wrap-exchange-contract.mdx @@ -0,0 +1,165 @@ +--- +title: Wrap Exchange Contract +description: Wrap the exchange contract to execute cross-chain swap operations. +updated: 2024-08-15 +authors: [0xstt] +icon: Terminal +--- + +In this course, we will wrap Trader Joe's Factory contract to execute swap operations on the destination chain. Trader Joe's exchange contracts are already deployed on Fuji, which why we are choosing Fuji as the destination chain. + +An example of the exchange wrapper code is provided below. This contract only allows swap operations on Trader Joe V1 pools or any other Uniswap V2-like contracts. + +Walkthrough: + +- The wrapper contract receives the payload via the `receiveTokens` function. +- The wrapper contract transfers the tokens to itself. +- The wrapper contract gets a quote from the exchange. +- The wrapper contract casts `payload` into `SwapOptions` struct. +- The wrapper contract checks if the received `amountOut` is greater than the `minAmountOut` requested when the contract was called from the source chain. +- The wrapper contract executes the swap operation and transfers the received asset to caller, depending on the preferred asset (wrapped token or native token). + +_Disclaimer: The avalanche-interchain-token-transfer contracts used in this tutorial are under active development and are not yet intended for production deployments. Use at your own risk._ + +```bash +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: Ecosystem + +pragma solidity 0.8.18; + +import {IERC20SendAndCallReceiver} from "../interfaces/IERC20SendAndCallReceiver.sol"; +import {SafeERC20TransferFrom} from "../utils/SafeERC20TransferFrom.sol"; +import {SafeERC20} from "@openzeppelin/contracts@4.8.1/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts@4.8.1/token/ERC20/IERC20.sol"; +import {Context} from "@openzeppelin/contracts@4.8.1/utils/Context.sol"; + +import {IWAVAX} from "./interface/IWAVAX.sol"; +import {IUniswapFactory} from "./interface/IUniswapFactory.sol"; +import {IUniswapPair} from "./interface/IUniswapPair.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +contract DexERC20Wrapper is Context, IERC20SendAndCallReceiver { + using SafeERC20 for IERC20; + + address public immutable WNATIVE; + address public immutable factory; + + struct SwapOptions { + address tokenOut; + uint256 minAmountOut; + } + + constructor( + address wrappedNativeAddress, + address dexFactoryAddress + ) { + WNATIVE = wrappedNativeAddress; + factory = dexFactoryAddress; + } + + event TokensReceived( + bytes32 indexed sourceBlockchainID, + address indexed originTokenTransferrerAddress, + address indexed originSenderAddress, + address token, + uint256 amount, + bytes payload + ); + + // To receive native when another contract called. + receive() external payable {} + + function getAmountOut( + uint256 amountIn, + uint256 reserveIn, + uint256 reserveOut + ) internal pure returns (uint256 amountOut) { + uint256 amountInWithFee = amountIn * 997; + uint256 numerator = amountInWithFee * reserveOut; + uint256 denominator = reserveIn * 1e3 + amountInWithFee; + amountOut = numerator / denominator; + } + + function query( + uint256 amountIn, + address tokenIn, + address tokenOut + ) internal view returns (uint256 amountOut) { + if (tokenIn == tokenOut || amountIn == 0) { + return 0; + } + address pair = IUniswapFactory(factory).getPair(tokenIn, tokenOut); + if (pair == address(0)) { + return 0; + } + (uint256 r0, uint256 r1, ) = IUniswapPair(pair).getReserves(); + (uint256 reserveIn, uint256 reserveOut) = tokenIn < tokenOut ? (r0, r1) : (r1, r0); + if (reserveIn > 0 && reserveOut > 0) { + amountOut = getAmountOut(amountIn, reserveIn, reserveOut); + } + } + + function swap( + uint256 amountIn, + uint256 amountOut, + address tokenIn, + address tokenOut, + address to + ) internal { + address pair = IUniswapFactory(factory).getPair(tokenIn, tokenOut); + (uint256 amount0Out, uint256 amount1Out) = (tokenIn < tokenOut) + ? (uint256(0), amountOut) : (amountOut, uint256(0)); + IERC20(tokenIn).safeTransfer(pair, amountIn); + IUniswapPair(pair).swap(amount0Out, amount1Out, to, new bytes(0)); + } + + function receiveTokens( + bytes32 sourceBlockchainID, + address originTokenTransferrerAddress, + address originSenderAddress, + address token, + uint256 amount, + bytes calldata payload + ) external { + emit TokensReceived({ + sourceBlockchainID: sourceBlockchainID, + originTokenTransferrerAddress: originTokenTransferrerAddress, + originSenderAddress: originSenderAddress, + token: token, + amount: amount, + payload: payload + }); + + require(payload.length > 0, "DexERC20Wrapper: empty payload"); + + IERC20 _token = IERC20(token); + // Receives teleported assets to be used for different purposes. + SafeERC20TransferFrom.safeTransferFrom(_token, _msgSender(), amount); + + // Requests a quote from the Uniswap V2-like contract. + uint256 amountOut = query(amount, token, WNATIVE); + require(amountOut > 0, "DexERC20Wrapper: insufficient liquidity"); + + // Parses the payload of the message. + SwapOptions memory swapOptions = abi.decode(payload, (SwapOptions)); + // Checks if the target swap price is still valid. + require(amountOut >= swapOptions.minAmountOut, "DexERC20Wrapper: slippage exceeded"); + + // Verifies if the desired tokenOut is a native or wrapped asset. + if (swapOptions.tokenOut == address(0)) { + swap(amount, amountOut, token, WNATIVE, address(this)); + IWAVAX(WNATIVE).withdraw(amountOut); + payable(originSenderAddress).transfer(amountOut); + } else { + swap(amount, amountOut, token, WNATIVE, originSenderAddress); + } + } + +} +``` \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/05-deploy-wrapped-exchange-contract.mdx b/content/course/interchain-token-transfer/12-send-and-call/05-deploy-wrapped-exchange-contract.mdx new file mode 100644 index 00000000..5db6816c --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/05-deploy-wrapped-exchange-contract.mdx @@ -0,0 +1,23 @@ +--- +title: Deploy Wrapped Exchange Contract +description: Deploy the DexERC20Wrapper on your own blockchain +updated: 2024-08-15 +authors: [0xstt] +icon: Terminal +--- + +While deploying the wrapped exchange contract, you will need to send two constructor arguments to the contract. + +- The first argument is the wrapped native token (WAVAX) address on the destination chain (Fuji), which is: [`0xd00ae08403B9bbb9124bB305C09058E32C39A48c`](https://testnet.snowtrace.io/address/0xd00ae08403B9bbb9124bB305C09058E32C39A48c). +- The second argument is the Trader Joe's (or any other Uniswap V2-like dapp) Factory V1 contract address on the destination chain (Fuji), which is: [`0xF5c7d9733e5f53abCC1695820c4818C59B457C2C`](https://testnet.snowtrace.io/address/0xF5c7d9733e5f53abCC1695820c4818C59B457C2C). Deployed contracts of TraderJoe can be found [here](https://docs.traderjoexyz.com/deployment-addresses/fuji). + +```bash +forge create --rpc-url https://api.avax-test.network/ext/bc/C/rpc --private-key $PK lib/{path}/DexERC20Wrapper.sol:DexERC20Wrapper --constructor-args 0xd00ae08403B9bbb9124bB305C09058E32C39A48c 0xF5c7d9733e5f53abCC1695820c4818C59B457C2C +``` + +Save the ```Deployed to``` address in an environment variable. + + +```bash +export WRAPPED_EXCHANGE_ADDRESS=<"Deployed to" address> +``` \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/06-deployment.mdx b/content/course/interchain-token-transfer/12-send-and-call/06-deployment.mdx new file mode 100644 index 00000000..c159f295 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/06-deployment.mdx @@ -0,0 +1,13 @@ +--- +title: Deployment +description: Find already deployed contract addresses. +updated: 2024-08-15 +authors: [0xstt] +icon: BookOpen +--- + +Here is the deployment address in case you skipped the deployment phase mentioned on the previous page. + +[`0x38B097d95B96CD17966Cf617A71b7B20F61ba85B`](https://testnet.snowtrace.io/address/0x38B097d95B96CD17966Cf617A71b7B20F61ba85B) + +You can call this contract from any other L1 as long as you have liquidity in the V1 pool on Trader Joe. \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/07-test-cross-chain-swap.mdx b/content/course/interchain-token-transfer/12-send-and-call/07-test-cross-chain-swap.mdx new file mode 100644 index 00000000..e2b55519 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/07-test-cross-chain-swap.mdx @@ -0,0 +1,39 @@ +--- +title: Test Cross Chain Swap +description: Trigger Cross Chain Swap from your L1. +updated: 2024-08-15 +authors: [0xstt] +icon: Terminal +--- + +Now that the wrapped exchange contract has been deployed, send an ERC20 token to execute a swap for WAVAX or AVAX from your Avalanche L1 to Fuji using the [`cast send`](https://book.getfoundry.sh/reference/cast/cast-send) command in foundry. + +```bash +cast send --rpc-url myblockchain --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAIN "sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" "(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_SUBNET}, ${WRAPPED_EXCHANGE_ADDRESS}, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, ${FUNDED_ADDRESS}, ${ERC20_HOME_TRANSFERER_C_CHAIN}, 0, 0)" 100000000000000000000 +``` + +The ```payload``` parameter that we sent can be generated via following JavaScript file: + +```bash +const { ethers } = require("ethers"); + +function encode() { + + const struct = { + tokenOut: "0xd00ae08403B9bbb9124bB305C09058E32C39A48c", + minAmountOut: 0 + }; + + const types = ["address", "uint256"]; + const encoded = ethers.AbiCoder.defaultAbiCoder().encode(types, [ struct.tokenOut, struct.minAmountOut ]); + + console.log(encoded); + +} + +encode(); +``` + +The transaction summary would look like this: + +![](/course-images/interchain-token-transfer/cross-chain-swap-tx-receipt.png) \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/send-and-call.mdx b/content/course/interchain-token-transfer/12-send-and-call/send-and-call.mdx deleted file mode 100644 index 4e2598e6..00000000 --- a/content/course/interchain-token-transfer/12-send-and-call/send-and-call.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Interchain Messaging Token Bridge -description: TBD -updated: 2024-05-31 -authors: [ashucoder9] -icon: Book ---- - -In addition to supporting basic token transfers, the token bridge contracts offer a `sendAndCall` interface for bridging tokens and using them in a smart contract interaction all within a single Interchain Messaging message. If the call to the recipient smart contract fails, the bridged tokens are sent to a fallback recipient address on the destination chain of the transfer. The `sendAndCall` interface enables the direct use of bridged tokens in dApps on other chains, such as performing swaps, using the tokens to pay for fees when invoking services, etc. diff --git a/content/course/interchain-token-transfer/meta.json b/content/course/interchain-token-transfer/meta.json index 82d217ff..6bcf2173 100644 --- a/content/course/interchain-token-transfer/meta.json +++ b/content/course/interchain-token-transfer/meta.json @@ -14,7 +14,9 @@ "---Interchain Token Transfer---", "...05-avalanche-interchain-token-transfer", "---ERC-20 to ERC-20 Token Bridge---", - "...06-erc-20-to-erc-20-bridge" + "...06-erc-20-to-erc-20-bridge", + "---Send and Call---", + "...12-send-and-call" ] } diff --git a/public/course-images/interchain-token-transfer/cross-chain-swap-tx-receipt.png b/public/course-images/interchain-token-transfer/cross-chain-swap-tx-receipt.png new file mode 100644 index 0000000000000000000000000000000000000000..c88d430eca72a5a3a2ce7b08ba111e44ff7e39e4 GIT binary patch literal 123751 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 Date: Fri, 23 Aug 2024 16:34:01 +0300 Subject: [PATCH 2/5] add simple example to send-and-call course, fix typo --- .../12-send-and-call/01-intro.mdx | 18 +++---- .../12-send-and-call/02-prerequisites.mdx | 8 +-- .../03-send-and-call-receivers.mdx | 28 ++++++++++- .../04-simple-example-mock-receivers.mdx | 50 +++++++++++++++++++ ...05-simple-example-deploy-mock-receiver.mdx | 21 ++++++++ .../06-simple-example-test-mock-receiver.mdx | 19 +++++++ ...vanced-example-wrap-exchange-contract.mdx} | 10 ++-- ...mple-deploy-wrapped-exchange-contract.mdx} | 8 +-- ...mdx => 09-advanced-example-deployment.mdx} | 4 +- ...dvanced-example-test-cross-chain-swap.mdx} | 6 +-- 10 files changed, 143 insertions(+), 29 deletions(-) create mode 100644 content/course/interchain-token-transfer/12-send-and-call/04-simple-example-mock-receivers.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/05-simple-example-deploy-mock-receiver.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/06-simple-example-test-mock-receiver.mdx rename content/course/interchain-token-transfer/12-send-and-call/{04-wrap-exchange-contract.mdx => 07-advanced-example-wrap-exchange-contract.mdx} (93%) rename content/course/interchain-token-transfer/12-send-and-call/{05-deploy-wrapped-exchange-contract.mdx => 08-advanced-example-deploy-wrapped-exchange-contract.mdx} (74%) rename content/course/interchain-token-transfer/12-send-and-call/{06-deployment.mdx => 09-advanced-example-deployment.mdx} (88%) rename content/course/interchain-token-transfer/12-send-and-call/{07-test-cross-chain-swap.mdx => 10-advanced-example-test-cross-chain-swap.mdx} (94%) diff --git a/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx b/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx index 37e34e4d..1657e3fe 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx @@ -1,22 +1,22 @@ --- title: Introduction description: Learn how to call another contract function after send tokens to another L1s. -updated: 2024-08-15 +updated: 2024-08-23 authors: [0xstt] icon: Book --- -In addition to supporting basic token transfers, the token bridge contracts offer a `sendAndCall` interface for bridging tokens and using them in a smart contract interaction all within a single Interchain Messaging message. If the call to the recipient smart contract fails, the bridged tokens are sent to a fallback recipient address on the destination chain of the transfer. The `sendAndCall` interface enables the direct use of bridged tokens in dApps on other chains, such as performing swaps, using the tokens to pay for fees when invoking services, etc. +In addition to supporting basic token transfers, the token transferrer contracts offer a `sendAndCall` interface for bridging tokens and using them in a smart contract interaction all within a single Interchain Messaging message. If the call to the recipient smart contract fails, the transferred tokens are sent to a fallback recipient address on the destination chain of the transfer. The `sendAndCall` interface enables the direct use of transferred tokens in dApps on other chains, such as performing swaps, using the tokens to pay for fees when invoking services, etc. -Teleporter Messenger has the ability to receive cross-chain messages on the destination chain and casts related messages to the `TeleporterMessage` struct. It then sends these messages to the Home/Remote Bridge contract, and handles them as `SEND` or `CALL`, as implemented in `TokenHome.sol` or `TokenRemote.sol`. +Teleporter Messenger has the ability to receive cross-chain messages on the destination chain and casts related messages to the `TeleporterMessage` struct. It then sends these messages to the Home/Remote Transferrer contract, and handles them as `SEND` or `CALL`, as implemented in `TokenHome.sol` or `TokenRemote.sol`. In this section we will cover the usage of the `CALL` message type with an example implementation. When `sendAndCall` function is triggered, the following actions are taken; -- The Bridge Contract grants an allowance to spend tokens on the destination contract. -- The Bridge Contract encodes the received message as parameters for the `receiveToken` function, as defined in the `IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` interface. -- The Bridge Contract checks whether the destination contract's function execution is successfull. -- The Bridge Contract retrieves the remaining allowance to check if there are any unspent tokens exists. -- The Bridge Contract removes the allowance for the destination contract. -- The Bridge Contract sends the remaining tokens to the fallback recipient. If the destination contract fails to execute the function, the full amount will be sent to the fallback recipient. \ No newline at end of file +- The Transferrer Contract grants an allowance to spend tokens on the destination contract. +- The Transferrer Contract encodes the received message as parameters for the `receiveToken` function, as defined in the `IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` interface. +- The Transferrer Contract checks whether the destination contract's function execution is successfull. +- The Transferrer Contract retrieves the remaining allowance to check if there are any unspent tokens exists. +- The Transferrer Contract removes the allowance for the destination contract. +- The Transferrer Contract sends the remaining tokens to the fallback recipient. If the destination contract fails to execute the function, the full amount will be sent to the fallback recipient. \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx b/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx index 07af4c82..290ee6f7 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx @@ -1,14 +1,14 @@ --- title: Prerequisites description: Here is what you need before starting this chapter. -updated: 2024-08-15 +updated: 2024-08-23 authors: [0xstt] icon: Book --- -The following prerequisites were covered im previous sections, so you should have already deployed the following contracts before starting this chapter: +The following prerequisites were covered in previous sections, so you should have already deployed the following contracts before starting this chapter: - Base ERC20 Token on L1 -- Home Bridge Contract on L1 -- Remote Bridge Contract on Fuji +- Home Transferrer Contract on L1 +- Remote Transferrer Contract on Fuji - A Running AWM-relayer from your L1 to Fuji diff --git a/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx b/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx index 2e3c1663..889bd8af 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx @@ -1,7 +1,7 @@ --- title: Send and Call Receivers description: Learn how tokens are received by the receivers. -updated: 2024-08-15 +updated: 2024-08-23 authors: [0xstt] icon: BookOpen --- @@ -12,7 +12,7 @@ Mock implementations are already available in the [Avalanche Interchain Token Tr What we are going to do is; simply deploy a new contract that implements the `IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` interfaces that has a capability to use received tokens. -```bash +```solidity title="lib/avalanche-interchain-token-transfer/contracts/src/interfaces/IERC20SendAndCallReceiver.sol" /** * @notice Interface for contracts that are called to receive token transfers. */ @@ -36,4 +36,28 @@ interface IERC20SendAndCallReceiver { bytes calldata payload ) external; } +``` + +```solidity title="lib/avalanche-interchain-token-transfer/contracts/src/interfaces/INativeSendAndCallReceiver.sol" +/** + * @notice Interface for a contracts that are called to receive native tokens. + */ +interface INativeSendAndCallReceiver { + /** + * @notice Called to receive the amount of the native token. Implementations + * must properly handle the msg.value of the call in order to ensure it doesn't + * become improperly made inaccessible. + * @param sourceBlockchainID Blockchain ID that the transfer originated from + * @param originTokenTransferrerAddress Address of the token transferrer that initiated the Teleporter message + * @param originSenderAddress Address of the sender that sent the transfer. This value + * should only be trusted if {originTokenTransferrerAddress} is verified and known. + * @param payload Arbitrary data provided by the caller + */ + function receiveTokens( + bytes32 sourceBlockchainID, + address originTokenTransferrerAddress, + address originSenderAddress, + bytes calldata payload + ) external payable; +} ``` \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/04-simple-example-mock-receivers.mdx b/content/course/interchain-token-transfer/12-send-and-call/04-simple-example-mock-receivers.mdx new file mode 100644 index 00000000..fe383a3a --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/04-simple-example-mock-receivers.mdx @@ -0,0 +1,50 @@ +--- +title: Simple Example - Mock Receivers +description: A brief overview of the mock ERC20 and native token receivers used for testing in sendAndCall functions. +updated: 2024-08-23 +authors: [0xstt] +icon: BookOpen +--- + +The primary purpose of these mock contracts is to test cross-chain token transfers and execute contract logic. These contracts implement the `IERC20SendAndCallReceiver` and `INativeSendAndCallReceiver` interfaces to handle token transfers, either for ERC20 tokens or native tokens, across Avalanche L1s. + +This contract only performs the following actions: + +- Checks if the message was received from a blocked sender. +- Emits a TokensReceived event. +- Checks if the payload is empty. +- Receives tokens to itself. + +_Disclaimer: The avalanche-interchain-token-transfer contracts used in this tutorial are under active development and are not yet intended for production deployments. Use at your own risk._ +_These contracts are simplistic, providing only the core functionality required for testing. Real-world implementations should consider additional security and token management features._ + +```solidity title="lib/avalanche-interchain-token-transfer/contracts/src/mocks/MockERC20SendAndCallReceiver.sol" + /** + * @dev See {IERC20SendAndCallReceiver-receiveTokens} + */ + function receiveTokens( + bytes32 sourceBlockchainID, + address originBridgeAddress, + address originSenderAddress, + address token, + uint256 amount, + bytes calldata payload + ) external { + require( + !blockedSenders[sourceBlockchainID][originSenderAddress], + "MockERC20SendAndCallReceiver: sender blocked" + ); + emit TokensReceived({ + sourceBlockchainID: sourceBlockchainID, + originBridgeAddress: originBridgeAddress, + originSenderAddress: originSenderAddress, + token: token, + amount: amount, + payload: payload + }); + + require(payload.length > 0, "MockERC20SendAndCallReceiver: empty payload"); + + SafeERC20TransferFrom.safeTransferFrom(IERC20(token), _msgSender(), amount); + } +``` \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/05-simple-example-deploy-mock-receiver.mdx b/content/course/interchain-token-transfer/12-send-and-call/05-simple-example-deploy-mock-receiver.mdx new file mode 100644 index 00000000..72971a17 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/05-simple-example-deploy-mock-receiver.mdx @@ -0,0 +1,21 @@ +--- +title: Simple Example - Deploy a Mock Receiver +description: Learn how to deploy a mock receiver contract. +updated: 2024-08-23 +authors: [0xstt] +icon: Terminal +--- + +In this section, you will deploy mock receiver contracts on the Avalanche L1. You can choose to deploy either the `MockERC20SendAndCallReceiver` or the `MockNativeSendAndCallReceiver` contract depending your token type. + +```bash +forge create --rpc-url myblockchain --private-key $PK lib/avalanche-interchain-token-transfer/contracts/src/mocks/MockERC20SendAndCallReceiver.sol:MockERC20SendAndCallReceiver +``` + +After deployment, save the `Deployed to` address in an environment variable for future use. + +```bash +export MOCK_RECEIVER_ADDRESS=<"Deployed to" address> +``` + +After successfully deploying the contract, move on to testing the mock receivers. \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/06-simple-example-test-mock-receiver.mdx b/content/course/interchain-token-transfer/12-send-and-call/06-simple-example-test-mock-receiver.mdx new file mode 100644 index 00000000..52229827 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/06-simple-example-test-mock-receiver.mdx @@ -0,0 +1,19 @@ +--- +title: Simple Example - Test Mock Receiver +description: Test cross-chain token transfers with mock receiver contracts. +updated: 2024-08-23 +authors: [0xstt] +icon: Terminal +--- + +Now that you have deployed the mock receiver contracts, it is time to test their functionality by sending tokens across Avalanche L1s. + +Use the following command to send tokens to the mock receiver contract: + +```bash +cast send --rpc-url myblockchain --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAIN "sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" "(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_SUBNET}, ${MOCK_RECEIVER_ADDRESS}, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, ${FUNDED_ADDRESS}, ${ERC20_HOME_TRANSFERER_C_CHAIN}, 0, 0)" 100000000000000000000 +``` + +### Verify the Results + +Check the logs and emitted events to verify that the tokens were received correctly. diff --git a/content/course/interchain-token-transfer/12-send-and-call/04-wrap-exchange-contract.mdx b/content/course/interchain-token-transfer/12-send-and-call/07-advanced-example-wrap-exchange-contract.mdx similarity index 93% rename from content/course/interchain-token-transfer/12-send-and-call/04-wrap-exchange-contract.mdx rename to content/course/interchain-token-transfer/12-send-and-call/07-advanced-example-wrap-exchange-contract.mdx index fc2a08f5..108b3739 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/04-wrap-exchange-contract.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/07-advanced-example-wrap-exchange-contract.mdx @@ -1,16 +1,16 @@ --- -title: Wrap Exchange Contract +title: Advanced Example - Wrap Exchange Contract description: Wrap the exchange contract to execute cross-chain swap operations. -updated: 2024-08-15 +updated: 2024-08-23 authors: [0xstt] icon: Terminal --- -In this course, we will wrap Trader Joe's Factory contract to execute swap operations on the destination chain. Trader Joe's exchange contracts are already deployed on Fuji, which why we are choosing Fuji as the destination chain. +In this example, we will wrap Trader Joe's Factory contract to execute swap operations on the destination chain. Trader Joe's exchange contracts are already deployed on Fuji, which why we are choosing Fuji as the destination chain. An example of the exchange wrapper code is provided below. This contract only allows swap operations on Trader Joe V1 pools or any other Uniswap V2-like contracts. -Walkthrough: +**Walkthrough**: - The wrapper contract receives the payload via the `receiveTokens` function. - The wrapper contract transfers the tokens to itself. @@ -21,7 +21,7 @@ Walkthrough: _Disclaimer: The avalanche-interchain-token-transfer contracts used in this tutorial are under active development and are not yet intended for production deployments. Use at your own risk._ -```bash +```solidity title="src/interchain-token-transfer/4-send-and-call/DexERC20Wrapper.sol" // (c) 2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. diff --git a/content/course/interchain-token-transfer/12-send-and-call/05-deploy-wrapped-exchange-contract.mdx b/content/course/interchain-token-transfer/12-send-and-call/08-advanced-example-deploy-wrapped-exchange-contract.mdx similarity index 74% rename from content/course/interchain-token-transfer/12-send-and-call/05-deploy-wrapped-exchange-contract.mdx rename to content/course/interchain-token-transfer/12-send-and-call/08-advanced-example-deploy-wrapped-exchange-contract.mdx index 5db6816c..aa95a8e0 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/05-deploy-wrapped-exchange-contract.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/08-advanced-example-deploy-wrapped-exchange-contract.mdx @@ -1,7 +1,7 @@ --- -title: Deploy Wrapped Exchange Contract +title: Advanced Example - Deploy Wrapped Exchange Contract description: Deploy the DexERC20Wrapper on your own blockchain -updated: 2024-08-15 +updated: 2024-08-23 authors: [0xstt] icon: Terminal --- @@ -12,10 +12,10 @@ While deploying the wrapped exchange contract, you will need to send two constru - The second argument is the Trader Joe's (or any other Uniswap V2-like dapp) Factory V1 contract address on the destination chain (Fuji), which is: [`0xF5c7d9733e5f53abCC1695820c4818C59B457C2C`](https://testnet.snowtrace.io/address/0xF5c7d9733e5f53abCC1695820c4818C59B457C2C). Deployed contracts of TraderJoe can be found [here](https://docs.traderjoexyz.com/deployment-addresses/fuji). ```bash -forge create --rpc-url https://api.avax-test.network/ext/bc/C/rpc --private-key $PK lib/{path}/DexERC20Wrapper.sol:DexERC20Wrapper --constructor-args 0xd00ae08403B9bbb9124bB305C09058E32C39A48c 0xF5c7d9733e5f53abCC1695820c4818C59B457C2C +forge create --rpc-url https://api.avax-test.network/ext/bc/C/rpc --private-key $PK src/interchain-token-transfer/4-send-and-call/DexERC20Wrapper.sol:DexERC20Wrapper --constructor-args 0xd00ae08403B9bbb9124bB305C09058E32C39A48c 0xF5c7d9733e5f53abCC1695820c4818C59B457C2C ``` -Save the ```Deployed to``` address in an environment variable. +Save the `Deployed to` address in an environment variable. ```bash diff --git a/content/course/interchain-token-transfer/12-send-and-call/06-deployment.mdx b/content/course/interchain-token-transfer/12-send-and-call/09-advanced-example-deployment.mdx similarity index 88% rename from content/course/interchain-token-transfer/12-send-and-call/06-deployment.mdx rename to content/course/interchain-token-transfer/12-send-and-call/09-advanced-example-deployment.mdx index c159f295..9166a09d 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/06-deployment.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/09-advanced-example-deployment.mdx @@ -1,7 +1,7 @@ --- -title: Deployment +title: Advanced Example - Deployment description: Find already deployed contract addresses. -updated: 2024-08-15 +updated: 2024-08-23 authors: [0xstt] icon: BookOpen --- diff --git a/content/course/interchain-token-transfer/12-send-and-call/07-test-cross-chain-swap.mdx b/content/course/interchain-token-transfer/12-send-and-call/10-advanced-example-test-cross-chain-swap.mdx similarity index 94% rename from content/course/interchain-token-transfer/12-send-and-call/07-test-cross-chain-swap.mdx rename to content/course/interchain-token-transfer/12-send-and-call/10-advanced-example-test-cross-chain-swap.mdx index e2b55519..2145286b 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/07-test-cross-chain-swap.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/10-advanced-example-test-cross-chain-swap.mdx @@ -1,7 +1,7 @@ --- -title: Test Cross Chain Swap +title: Advanced Example - Test Cross Chain Swap description: Trigger Cross Chain Swap from your L1. -updated: 2024-08-15 +updated: 2024-08-23 authors: [0xstt] icon: Terminal --- @@ -14,7 +14,7 @@ cast send --rpc-url myblockchain --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAI The ```payload``` parameter that we sent can be generated via following JavaScript file: -```bash +```typescript const { ethers } = require("ethers"); function encode() { From 00acf0789cbeffdaa6dd7d671faaebde6dbbefcc Mon Sep 17 00:00:00 2001 From: Martin Eckardt Date: Wed, 4 Sep 2024 16:01:24 -0400 Subject: [PATCH 3/5] Small structure changes --- .../12-send-and-call/01-intro.mdx | 11 ++- .../12-send-and-call/02-prerequisites.mdx | 14 --- .../03-send-and-call-receivers.mdx | 10 +- .../12-send-and-call/04-mock-receivers.mdx | 93 ++++++++++++++++++ .../04-simple-example-mock-receivers.mdx | 50 ---------- .../12-send-and-call/05-mock-receiver.mdx | 61 ++++++++++++ ...05-simple-example-deploy-mock-receiver.mdx | 21 ---- .../06-simple-example-test-mock-receiver.mdx | 19 ---- ...ample-deploy-wrapped-exchange-contract.mdx | 23 ----- .../09-advanced-example-deployment.mdx | 13 --- ...advanced-example-test-cross-chain-swap.mdx | 39 -------- .../07-exchange-contract.mdx} | 4 +- .../08-deploy-wrapped-exchange-contract.mdx | 97 +++++++++++++++++++ .../interchain-token-transfer/meta.json | 4 +- 14 files changed, 273 insertions(+), 186 deletions(-) delete mode 100644 content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/04-mock-receivers.mdx delete mode 100644 content/course/interchain-token-transfer/12-send-and-call/04-simple-example-mock-receivers.mdx create mode 100644 content/course/interchain-token-transfer/12-send-and-call/05-mock-receiver.mdx delete mode 100644 content/course/interchain-token-transfer/12-send-and-call/05-simple-example-deploy-mock-receiver.mdx delete mode 100644 content/course/interchain-token-transfer/12-send-and-call/06-simple-example-test-mock-receiver.mdx delete mode 100644 content/course/interchain-token-transfer/12-send-and-call/08-advanced-example-deploy-wrapped-exchange-contract.mdx delete mode 100644 content/course/interchain-token-transfer/12-send-and-call/09-advanced-example-deployment.mdx delete mode 100644 content/course/interchain-token-transfer/12-send-and-call/10-advanced-example-test-cross-chain-swap.mdx rename content/course/interchain-token-transfer/{12-send-and-call/07-advanced-example-wrap-exchange-contract.mdx => 13-cross-chain-token-swaps/07-exchange-contract.mdx} (98%) create mode 100644 content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx diff --git a/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx b/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx index 1657e3fe..d8219aa8 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/01-intro.mdx @@ -19,4 +19,13 @@ When `sendAndCall` function is triggered, the following actions are taken; - The Transferrer Contract checks whether the destination contract's function execution is successfull. - The Transferrer Contract retrieves the remaining allowance to check if there are any unspent tokens exists. - The Transferrer Contract removes the allowance for the destination contract. -- The Transferrer Contract sends the remaining tokens to the fallback recipient. If the destination contract fails to execute the function, the full amount will be sent to the fallback recipient. \ No newline at end of file +- The Transferrer Contract sends the remaining tokens to the fallback recipient. If the destination contract fails to execute the function, the full amount will be sent to the fallback recipient. + +## Prerequisites + +The following prerequisites were covered in previous sections, so you should have already deployed the following contracts before starting this chapter: + +- Base ERC20 Token on L1 +- Home Transferrer Contract on L1 +- Remote Transferrer Contract on Fuji +- A Running AWM-relayer from your L1 to Fuji diff --git a/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx b/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx deleted file mode 100644 index 290ee6f7..00000000 --- a/content/course/interchain-token-transfer/12-send-and-call/02-prerequisites.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Prerequisites -description: Here is what you need before starting this chapter. -updated: 2024-08-23 -authors: [0xstt] -icon: Book ---- - -The following prerequisites were covered in previous sections, so you should have already deployed the following contracts before starting this chapter: - -- Base ERC20 Token on L1 -- Home Transferrer Contract on L1 -- Remote Transferrer Contract on Fuji -- A Running AWM-relayer from your L1 to Fuji diff --git a/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx b/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx index 889bd8af..5852e342 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/03-send-and-call-receivers.mdx @@ -6,11 +6,11 @@ authors: [0xstt] icon: BookOpen --- -`IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` are used for contracts that handle receiving ERC20 or native tokens. +The interfaces `IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` are used for contracts that handle receiving ERC20 or native tokens of the Interchain Token Transfer protocol. They are similar to the `ITeleporterReceiver` interface, but they are specifically designed to handle token transfers. -Mock implementations are already available in the [Avalanche Interchain Token Transfer](https://github.com/ava-labs/avalanche-interchain-token-transfer) repository. +### IERC20SendAndCallReceiver -What we are going to do is; simply deploy a new contract that implements the `IERC20SendAndCallReceiver` or `INativeSendAndCallReceiver` interfaces that has a capability to use received tokens. +The `receiveTokens` function will be called by the Transferrer bridge contract. The contract must implement this function to receive the tokens and can retrieve all the information about the origin of the tokens, the token, the bridge used, and the amount of tokens transferred from the parameters. ```solidity title="lib/avalanche-interchain-token-transfer/contracts/src/interfaces/IERC20SendAndCallReceiver.sol" /** @@ -38,6 +38,10 @@ interface IERC20SendAndCallReceiver { } ``` +### INativeSendAndCallReceiver + +The `INativeSendAndCallReceiver` interface is used for contracts that handle receiving native tokens of the Interchain Token Transfer protocol. It is similar to the `IERC20SendAndCallReceiver` interface, but does not include the `token` and `amount` parameters. The `receiveTokens` is now `payable`. There is only a single native token on each chain, so the address is not needed. The amount can be determined from calling `msg.value`. + ```solidity title="lib/avalanche-interchain-token-transfer/contracts/src/interfaces/INativeSendAndCallReceiver.sol" /** * @notice Interface for a contracts that are called to receive native tokens. diff --git a/content/course/interchain-token-transfer/12-send-and-call/04-mock-receivers.mdx b/content/course/interchain-token-transfer/12-send-and-call/04-mock-receivers.mdx new file mode 100644 index 00000000..294710e5 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/04-mock-receivers.mdx @@ -0,0 +1,93 @@ +--- +title: Mock Receivers +description: A brief overview of the mock ERC20 and native token receivers used for testing in sendAndCall functions. +updated: 2024-08-23 +authors: [0xstt] +icon: BookOpen +--- + +The primary purpose of these mock contracts is to test cross-chain token transfers and execute contract logic. These contracts implement the `IERC20SendAndCallReceiver` and `INativeSendAndCallReceiver` interfaces to handle token transfers, either for ERC20 tokens or native tokens, across Avalanche L1s. + +This contract only performs the following actions: + +- Checks if the message was received from a blocked sender. +- Emits a TokensReceived event. +- Checks if the payload is empty. +- Receives tokens to itself. + +```solidity title="lib/avalanche-interchain-token-transfer/contracts/src/mocks/MockERC20SendAndCallReceiver.sol" +pragma solidity 0.8.25; + +import {IERC20SendAndCallReceiver} from "../interfaces/IERC20SendAndCallReceiver.sol"; +import {SafeERC20TransferFrom} from "../utils/SafeERC20TransferFrom.sol"; +import {SafeERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/IERC20.sol"; +import {Context} from "@openzeppelin/contracts@5.0.2/utils/Context.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +/** + * @notice This is mock implementation of {receiveTokens} to be used in tests. + * This contract DOES NOT provide a mechanism for accessing the tokens transfered to it. + * Real implementations must ensure that tokens are properly handled and not incorrectly locked. + */ +contract MockERC20SendAndCallReceiver is Context, IERC20SendAndCallReceiver { + using SafeERC20 for IERC20; + + mapping(bytes32 blockchainID => mapping(address senderAddress => bool blocked)) public + blockedSenders; + + /** + * @dev Emitted when receiveTokens is called. + */ + event TokensReceived( + bytes32 indexed sourceBlockchainID, + address indexed originTokenTransferrerAddress, + address indexed originSenderAddress, + address token, + uint256 amount, + bytes payload + ); + + /** // [!code highlight:28] + * @dev See {IERC20SendAndCallReceiver-receiveTokens} + */ + function receiveTokens( + bytes32 sourceBlockchainID, + address originTokenTransferrerAddress, + address originSenderAddress, + address token, + uint256 amount, + bytes calldata payload + ) external { + require( + !blockedSenders[sourceBlockchainID][originSenderAddress], + "MockERC20SendAndCallReceiver: sender blocked" + ); + emit TokensReceived({ + sourceBlockchainID: sourceBlockchainID, + originTokenTransferrerAddress: originTokenTransferrerAddress, + originSenderAddress: originSenderAddress, + token: token, + amount: amount, + payload: payload + }); + + require(payload.length > 0, "MockERC20SendAndCallReceiver: empty payload"); + + SafeERC20TransferFrom.safeTransferFrom(IERC20(token), _msgSender(), amount); + } + + /** + * @notice Block a sender from sending tokens to this contract. + * @param blockchainID The blockchain ID of the sender. + * @param senderAddress The address of the sender. + */ + function blockSender(bytes32 blockchainID, address senderAddress) external { + blockedSenders[blockchainID][senderAddress] = true; + } +} +``` \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/04-simple-example-mock-receivers.mdx b/content/course/interchain-token-transfer/12-send-and-call/04-simple-example-mock-receivers.mdx deleted file mode 100644 index fe383a3a..00000000 --- a/content/course/interchain-token-transfer/12-send-and-call/04-simple-example-mock-receivers.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Simple Example - Mock Receivers -description: A brief overview of the mock ERC20 and native token receivers used for testing in sendAndCall functions. -updated: 2024-08-23 -authors: [0xstt] -icon: BookOpen ---- - -The primary purpose of these mock contracts is to test cross-chain token transfers and execute contract logic. These contracts implement the `IERC20SendAndCallReceiver` and `INativeSendAndCallReceiver` interfaces to handle token transfers, either for ERC20 tokens or native tokens, across Avalanche L1s. - -This contract only performs the following actions: - -- Checks if the message was received from a blocked sender. -- Emits a TokensReceived event. -- Checks if the payload is empty. -- Receives tokens to itself. - -_Disclaimer: The avalanche-interchain-token-transfer contracts used in this tutorial are under active development and are not yet intended for production deployments. Use at your own risk._ -_These contracts are simplistic, providing only the core functionality required for testing. Real-world implementations should consider additional security and token management features._ - -```solidity title="lib/avalanche-interchain-token-transfer/contracts/src/mocks/MockERC20SendAndCallReceiver.sol" - /** - * @dev See {IERC20SendAndCallReceiver-receiveTokens} - */ - function receiveTokens( - bytes32 sourceBlockchainID, - address originBridgeAddress, - address originSenderAddress, - address token, - uint256 amount, - bytes calldata payload - ) external { - require( - !blockedSenders[sourceBlockchainID][originSenderAddress], - "MockERC20SendAndCallReceiver: sender blocked" - ); - emit TokensReceived({ - sourceBlockchainID: sourceBlockchainID, - originBridgeAddress: originBridgeAddress, - originSenderAddress: originSenderAddress, - token: token, - amount: amount, - payload: payload - }); - - require(payload.length > 0, "MockERC20SendAndCallReceiver: empty payload"); - - SafeERC20TransferFrom.safeTransferFrom(IERC20(token), _msgSender(), amount); - } -``` \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/05-mock-receiver.mdx b/content/course/interchain-token-transfer/12-send-and-call/05-mock-receiver.mdx new file mode 100644 index 00000000..46937115 --- /dev/null +++ b/content/course/interchain-token-transfer/12-send-and-call/05-mock-receiver.mdx @@ -0,0 +1,61 @@ +--- +title: Deploy a Mock Receiver +description: Learn how to deploy a mock receiver contract. +updated: 2024-08-23 +authors: [0xstt] +icon: Terminal +--- +import { Step, Steps } from 'fumadocs-ui/components/steps'; + +In this section, you will deploy mock receiver contracts on the Avalanche L1. + + + + +### Receiver Deployment + +You can choose to deploy either the `MockERC20SendAndCallReceiver` or the `MockNativeSendAndCallReceiver` contract depending your token type. + +```bash +forge create --rpc-url myblockchain --private-key $PK lib/avalanche-interchain-token-transfer/contracts/src/mocks/MockERC20SendAndCallReceiver.sol:MockERC20SendAndCallReceiver +``` + + + + +### Save Receiver Address + +After deployment, save the `Deployed to` address in an environment variable for future use. + +```bash +export MOCK_RECEIVER_ADDRESS=
+``` + + + + +### Send Tokens + +Use the following command to send tokens to the mock receiver contract: + +```bash +cast send --rpc-url myblockchain --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAIN \ +"sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" \ +"(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_SUBNET}, ${MOCK_RECEIVER_ADDRESS}, \ +0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, \ +${FUNDED_ADDRESS}, ${ERC20_HOME_TRANSFERER_C_CHAIN}, 0, 0)" 100000000000000000000 +``` + + + + +### Verify the Results + +Check the logs and emitted events to verify that the tokens were received correctly. + +TBD: Provide instructions + + + + +After successfully deploying the contract, move on to testing the mock receivers. \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/05-simple-example-deploy-mock-receiver.mdx b/content/course/interchain-token-transfer/12-send-and-call/05-simple-example-deploy-mock-receiver.mdx deleted file mode 100644 index 72971a17..00000000 --- a/content/course/interchain-token-transfer/12-send-and-call/05-simple-example-deploy-mock-receiver.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: Simple Example - Deploy a Mock Receiver -description: Learn how to deploy a mock receiver contract. -updated: 2024-08-23 -authors: [0xstt] -icon: Terminal ---- - -In this section, you will deploy mock receiver contracts on the Avalanche L1. You can choose to deploy either the `MockERC20SendAndCallReceiver` or the `MockNativeSendAndCallReceiver` contract depending your token type. - -```bash -forge create --rpc-url myblockchain --private-key $PK lib/avalanche-interchain-token-transfer/contracts/src/mocks/MockERC20SendAndCallReceiver.sol:MockERC20SendAndCallReceiver -``` - -After deployment, save the `Deployed to` address in an environment variable for future use. - -```bash -export MOCK_RECEIVER_ADDRESS=<"Deployed to" address> -``` - -After successfully deploying the contract, move on to testing the mock receivers. \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/06-simple-example-test-mock-receiver.mdx b/content/course/interchain-token-transfer/12-send-and-call/06-simple-example-test-mock-receiver.mdx deleted file mode 100644 index 52229827..00000000 --- a/content/course/interchain-token-transfer/12-send-and-call/06-simple-example-test-mock-receiver.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: Simple Example - Test Mock Receiver -description: Test cross-chain token transfers with mock receiver contracts. -updated: 2024-08-23 -authors: [0xstt] -icon: Terminal ---- - -Now that you have deployed the mock receiver contracts, it is time to test their functionality by sending tokens across Avalanche L1s. - -Use the following command to send tokens to the mock receiver contract: - -```bash -cast send --rpc-url myblockchain --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAIN "sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" "(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_SUBNET}, ${MOCK_RECEIVER_ADDRESS}, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, ${FUNDED_ADDRESS}, ${ERC20_HOME_TRANSFERER_C_CHAIN}, 0, 0)" 100000000000000000000 -``` - -### Verify the Results - -Check the logs and emitted events to verify that the tokens were received correctly. diff --git a/content/course/interchain-token-transfer/12-send-and-call/08-advanced-example-deploy-wrapped-exchange-contract.mdx b/content/course/interchain-token-transfer/12-send-and-call/08-advanced-example-deploy-wrapped-exchange-contract.mdx deleted file mode 100644 index aa95a8e0..00000000 --- a/content/course/interchain-token-transfer/12-send-and-call/08-advanced-example-deploy-wrapped-exchange-contract.mdx +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: Advanced Example - Deploy Wrapped Exchange Contract -description: Deploy the DexERC20Wrapper on your own blockchain -updated: 2024-08-23 -authors: [0xstt] -icon: Terminal ---- - -While deploying the wrapped exchange contract, you will need to send two constructor arguments to the contract. - -- The first argument is the wrapped native token (WAVAX) address on the destination chain (Fuji), which is: [`0xd00ae08403B9bbb9124bB305C09058E32C39A48c`](https://testnet.snowtrace.io/address/0xd00ae08403B9bbb9124bB305C09058E32C39A48c). -- The second argument is the Trader Joe's (or any other Uniswap V2-like dapp) Factory V1 contract address on the destination chain (Fuji), which is: [`0xF5c7d9733e5f53abCC1695820c4818C59B457C2C`](https://testnet.snowtrace.io/address/0xF5c7d9733e5f53abCC1695820c4818C59B457C2C). Deployed contracts of TraderJoe can be found [here](https://docs.traderjoexyz.com/deployment-addresses/fuji). - -```bash -forge create --rpc-url https://api.avax-test.network/ext/bc/C/rpc --private-key $PK src/interchain-token-transfer/4-send-and-call/DexERC20Wrapper.sol:DexERC20Wrapper --constructor-args 0xd00ae08403B9bbb9124bB305C09058E32C39A48c 0xF5c7d9733e5f53abCC1695820c4818C59B457C2C -``` - -Save the `Deployed to` address in an environment variable. - - -```bash -export WRAPPED_EXCHANGE_ADDRESS=<"Deployed to" address> -``` \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/09-advanced-example-deployment.mdx b/content/course/interchain-token-transfer/12-send-and-call/09-advanced-example-deployment.mdx deleted file mode 100644 index 9166a09d..00000000 --- a/content/course/interchain-token-transfer/12-send-and-call/09-advanced-example-deployment.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Advanced Example - Deployment -description: Find already deployed contract addresses. -updated: 2024-08-23 -authors: [0xstt] -icon: BookOpen ---- - -Here is the deployment address in case you skipped the deployment phase mentioned on the previous page. - -[`0x38B097d95B96CD17966Cf617A71b7B20F61ba85B`](https://testnet.snowtrace.io/address/0x38B097d95B96CD17966Cf617A71b7B20F61ba85B) - -You can call this contract from any other L1 as long as you have liquidity in the V1 pool on Trader Joe. \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/10-advanced-example-test-cross-chain-swap.mdx b/content/course/interchain-token-transfer/12-send-and-call/10-advanced-example-test-cross-chain-swap.mdx deleted file mode 100644 index 2145286b..00000000 --- a/content/course/interchain-token-transfer/12-send-and-call/10-advanced-example-test-cross-chain-swap.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Advanced Example - Test Cross Chain Swap -description: Trigger Cross Chain Swap from your L1. -updated: 2024-08-23 -authors: [0xstt] -icon: Terminal ---- - -Now that the wrapped exchange contract has been deployed, send an ERC20 token to execute a swap for WAVAX or AVAX from your Avalanche L1 to Fuji using the [`cast send`](https://book.getfoundry.sh/reference/cast/cast-send) command in foundry. - -```bash -cast send --rpc-url myblockchain --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAIN "sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" "(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_SUBNET}, ${WRAPPED_EXCHANGE_ADDRESS}, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, ${FUNDED_ADDRESS}, ${ERC20_HOME_TRANSFERER_C_CHAIN}, 0, 0)" 100000000000000000000 -``` - -The ```payload``` parameter that we sent can be generated via following JavaScript file: - -```typescript -const { ethers } = require("ethers"); - -function encode() { - - const struct = { - tokenOut: "0xd00ae08403B9bbb9124bB305C09058E32C39A48c", - minAmountOut: 0 - }; - - const types = ["address", "uint256"]; - const encoded = ethers.AbiCoder.defaultAbiCoder().encode(types, [ struct.tokenOut, struct.minAmountOut ]); - - console.log(encoded); - -} - -encode(); -``` - -The transaction summary would look like this: - -![](/course-images/interchain-token-transfer/cross-chain-swap-tx-receipt.png) \ No newline at end of file diff --git a/content/course/interchain-token-transfer/12-send-and-call/07-advanced-example-wrap-exchange-contract.mdx b/content/course/interchain-token-transfer/13-cross-chain-token-swaps/07-exchange-contract.mdx similarity index 98% rename from content/course/interchain-token-transfer/12-send-and-call/07-advanced-example-wrap-exchange-contract.mdx rename to content/course/interchain-token-transfer/13-cross-chain-token-swaps/07-exchange-contract.mdx index 108b3739..d1b5a20e 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/07-advanced-example-wrap-exchange-contract.mdx +++ b/content/course/interchain-token-transfer/13-cross-chain-token-swaps/07-exchange-contract.mdx @@ -1,9 +1,9 @@ --- -title: Advanced Example - Wrap Exchange Contract +title: Wrap Exchange Contract description: Wrap the exchange contract to execute cross-chain swap operations. updated: 2024-08-23 authors: [0xstt] -icon: Terminal +icon: Book --- In this example, we will wrap Trader Joe's Factory contract to execute swap operations on the destination chain. Trader Joe's exchange contracts are already deployed on Fuji, which why we are choosing Fuji as the destination chain. diff --git a/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx b/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx new file mode 100644 index 00000000..6a433870 --- /dev/null +++ b/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx @@ -0,0 +1,97 @@ +--- +title: Deploy Wrapped Exchange Contract +description: Deploy the DexERC20Wrapper on your own blockchain +updated: 2024-08-23 +authors: [0xstt] +icon: Terminal +--- + +import { Step, Steps } from 'fumadocs-ui/components/steps'; +import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; + +Let's deploy our wrapper for the exchange contract on your own blockchain. + + + + +### Wrapper Deployment + +While deploying the wrapped exchange contract, you will need to send two constructor arguments to the contract. + +- The first argument is the wrapped native token (WAVAX) address on the destination chain (Fuji), which is: [`0xd00ae08403B9bbb9124bB305C09058E32C39A48c`](https://testnet.snowtrace.io/address/0xd00ae08403B9bbb9124bB305C09058E32C39A48c). +- The second argument is the Trader Joe's (or any other Uniswap V2-like dapp) Factory V1 contract address on the destination chain (Fuji), which is: [`0xF5c7d9733e5f53abCC1695820c4818C59B457C2C`](https://testnet.snowtrace.io/address/0xF5c7d9733e5f53abCC1695820c4818C59B457C2C). Deployed contracts of TraderJoe can be found [here](https://docs.traderjoexyz.com/deployment-addresses/fuji). + +```bash +forge create --rpc-url local-c --private-key $PK src/interchain-token-transfer/4-send-and-call/DexERC20Wrapper.sol:DexERC20Wrapper --constructor-args 0xd00ae08403B9bbb9124bB305C09058E32C39A48c 0xF5c7d9733e5f53abCC1695820c4818C59B457C2C +``` + + + + +### Save the Wrapper Address + +Save the `Deployed to` address in an environment variable. + + +```bash +export WRAPPED_EXCHANGE_ADDRESS=
+``` + +In case you skipped the deployment phase mentioned on the previous page, you can use a wrapper contract, that is already deployed at [`0x38B097d95B96CD17966Cf617A71b7B20F61ba85B`](https://testnet.snowtrace.io/address/0x38B097d95B96CD17966Cf617A71b7B20F61ba85B). + +```bash +export WRAPPED_EXCHANGE_ADDRESS=0x38B097d95B96CD17966Cf617A71b7B20F61ba85B +``` + + + + +### Initiate the Cross-Chain Swap + +Now that the wrapped exchange contract has been deployed, send an ERC20 token to execute a swap for WAVAX or AVAX from your Avalanche L1 to Fuji using the [`cast send`](https://book.getfoundry.sh/reference/cast/cast-send) command in foundry. + +```bash +cast send --rpc-url echo --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAIN "sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" "(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_SUBNET}, ${WRAPPED_EXCHANGE_ADDRESS}, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, ${FUNDED_ADDRESS}, ${ERC20_HOME_TRANSFERER_C_CHAIN}, 0, 0)" 100000000000000000000 +``` + + + + +The ```payload``` parameter that we sent can be generated via following JavaScript file: + +```typescript +const { ethers } = require("ethers"); + +function encode() { + + const struct = { + tokenOut: "0xd00ae08403B9bbb9124bB305C09058E32C39A48c", + minAmountOut: 0 + }; + + const types = ["address", "uint256"]; + const encoded = ethers.AbiCoder.defaultAbiCoder().encode(types, [ struct.tokenOut, struct.minAmountOut ]); + + console.log(encoded); + +} + +encode(); +``` + + + + + + + +### Verify the Results + +TBD: Provide instructions + + + + + + + diff --git a/content/course/interchain-token-transfer/meta.json b/content/course/interchain-token-transfer/meta.json index 6bcf2173..7de0102c 100644 --- a/content/course/interchain-token-transfer/meta.json +++ b/content/course/interchain-token-transfer/meta.json @@ -16,7 +16,9 @@ "---ERC-20 to ERC-20 Token Bridge---", "...06-erc-20-to-erc-20-bridge", "---Send and Call---", - "...12-send-and-call" + "...12-send-and-call", + "---Cross-Chain Token Swaps---", + "...13-cross-chain-token-swaps" ] } From 9c84feb57cac7c53b6bccd45d881d18b17926d6f Mon Sep 17 00:00:00 2001 From: owenwahlgren Date: Thu, 5 Sep 2024 13:58:44 -0400 Subject: [PATCH 4/5] fix: env variables --- .../12-send-and-call/05-mock-receiver.mdx | 6 ++---- .../08-deploy-wrapped-exchange-contract.mdx | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/content/course/interchain-token-transfer/12-send-and-call/05-mock-receiver.mdx b/content/course/interchain-token-transfer/12-send-and-call/05-mock-receiver.mdx index 46937115..b92a8aa7 100644 --- a/content/course/interchain-token-transfer/12-send-and-call/05-mock-receiver.mdx +++ b/content/course/interchain-token-transfer/12-send-and-call/05-mock-receiver.mdx @@ -39,11 +39,9 @@ export MOCK_RECEIVER_ADDRESS=
Use the following command to send tokens to the mock receiver contract: ```bash -cast send --rpc-url myblockchain --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAIN \ +cast send --rpc-url myblockchain --private-key $PK $ERC20_HOME_C_CHAIN \ "sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" \ -"(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_SUBNET}, ${MOCK_RECEIVER_ADDRESS}, \ -0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, \ -${FUNDED_ADDRESS}, ${ERC20_HOME_TRANSFERER_C_CHAIN}, 0, 0)" 100000000000000000000 +"(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_L1}, ${MOCK_RECEIVER_ADDRESS}, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, ${FUNDED_ADDRESS}, ${ERC20_HOME_C_CHAIN}, 0, 0)" 100000000000000000000 ``` diff --git a/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx b/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx index 6a433870..14ffac73 100644 --- a/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx +++ b/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx @@ -51,7 +51,7 @@ export WRAPPED_EXCHANGE_ADDRESS=0x38B097d95B96CD17966Cf617A71b7B20F61ba85B Now that the wrapped exchange contract has been deployed, send an ERC20 token to execute a swap for WAVAX or AVAX from your Avalanche L1 to Fuji using the [`cast send`](https://book.getfoundry.sh/reference/cast/cast-send) command in foundry. ```bash -cast send --rpc-url echo --private-key $PK $ERC20_HOME_TRANSFERER_C_CHAIN "sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" "(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_SUBNET}, ${WRAPPED_EXCHANGE_ADDRESS}, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, ${FUNDED_ADDRESS}, ${ERC20_HOME_TRANSFERER_C_CHAIN}, 0, 0)" 100000000000000000000 +cast send --rpc-url echo --private-key $PK $ERC20_HOME_C_CHAIN "sendAndCall((bytes32, address, address, bytes, uint256, uint256, address, address, address, uint256, uint256), uint256)" "(${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${ERC20_TOKEN_REMOTE_L1}, ${WRAPPED_EXCHANGE_ADDRESS}, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2500000, 2000000, 0x0000000000000000000000000000000000000000, ${FUNDED_ADDRESS}, ${ERC20_HOME_C_CHAIN}, 0, 0)" 100000000000000000000 ``` From 434862374f1e98a7a48769be28083f68cb693215 Mon Sep 17 00:00:00 2001 From: owenwahlgren Date: Thu, 5 Sep 2024 14:34:56 -0400 Subject: [PATCH 5/5] fix: DexERC20Wrapper.sol path --- .../08-deploy-wrapped-exchange-contract.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx b/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx index 14ffac73..e77a21fe 100644 --- a/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx +++ b/content/course/interchain-token-transfer/13-cross-chain-token-swaps/08-deploy-wrapped-exchange-contract.mdx @@ -22,7 +22,7 @@ While deploying the wrapped exchange contract, you will need to send two constru - The second argument is the Trader Joe's (or any other Uniswap V2-like dapp) Factory V1 contract address on the destination chain (Fuji), which is: [`0xF5c7d9733e5f53abCC1695820c4818C59B457C2C`](https://testnet.snowtrace.io/address/0xF5c7d9733e5f53abCC1695820c4818C59B457C2C). Deployed contracts of TraderJoe can be found [here](https://docs.traderjoexyz.com/deployment-addresses/fuji). ```bash -forge create --rpc-url local-c --private-key $PK src/interchain-token-transfer/4-send-and-call/DexERC20Wrapper.sol:DexERC20Wrapper --constructor-args 0xd00ae08403B9bbb9124bB305C09058E32C39A48c 0xF5c7d9733e5f53abCC1695820c4818C59B457C2C +forge create --rpc-url local-c --private-key $PK src/10-cross-chain-token-swaps/DexERC20Wrapper.sol:DexERC20Wrapper --constructor-args 0xd00ae08403B9bbb9124bB305C09058E32C39A48c 0xF5c7d9733e5f53abCC1695820c4818C59B457C2C ```