diff --git a/src/MultichainEcommerce/Build an Avalanche L1 for Payments with USDC 34a6c721e1344ddfa83b27c66b665040.md b/src/MultichainEcommerce/Build an Avalanche L1 for Payments with USDC 34a6c721e1344ddfa83b27c66b665040.md new file mode 100644 index 00000000..6390c512 --- /dev/null +++ b/src/MultichainEcommerce/Build an Avalanche L1 for Payments with USDC 34a6c721e1344ddfa83b27c66b665040.md @@ -0,0 +1,765 @@ +# Build an Avalanche L1 for Payments with USDC + +Welcome to this guide on building an Avalanche Layer 1 (L1) network for payments with USDC (USD Coin). In this tutorial, we’ll walk through how to utilize Avalanche’s fast and cost-efficient infrastructure to develop a reliable payment solution backed by the stability of USDC. Whether you’re creating a new payment platform or enhancing an existing one, this guide will provide key steps and insights to integrate USDC on Avalanche, ensuring seamless and scalable transactions. + +To follow along with this guide, you’ll need the following tools: + +- **Avalanche CLI** for creating L1, +- **AvalancheGo** to run a validator for your L1, +- **AWM Relayer** for handling messaging across chains. + +We'll start by setting up AvalancheGo. + +## Installing AvalancheGo + +AvalancheGo enables us to run validator nodes and participate in the consensus mechanism. + +Let’s begin with the installation of AvalancheGo: + +```bash +wget -nd -m https://raw.githubusercontent.com/ava-labs/avalanche-docs/master/scripts/avalanchego-installer.sh;\ +chmod 755 avalanchego-installer.sh;\ +./avalanchego-installer.sh +``` + +Once you run the script, you will see output similar to this: + +```bash +AvalancheGo installer +--------------------- +Preparing environment... +Found arm64 architecture... +Looking for the latest arm64 build... +Attempting to download: + https://github.com/ava-labs/avalanchego/releases/download/v1.11.11/avalanchego-linux-amd64-v1.11.11.tar.gz +avalanchego-linux-amd64-v1.11.11.tar.gz 100%[===========================================>] 35.05M 35.4MB/s in 1.0s +... +Node files unpacked into /home/subnet/avalanche-node + +``` + +The setup will prompt you for some network configuration: + +1. **Choose your network type**: + - `1)` for a residential network (dynamic IP) + - `2)` for a cloud provider (static IP) +2. **Verify your public IP**: + - The setup will auto-detect your IP address. Confirm whether the detected IP is correct by entering `y` or `n`. +3. **Set your RPC port**: + - For public interaction, select `public`, or for a private validator node, select `private`. +4. **Enable state sync bootstrapping**: + - Turning this `on` will speed up bootstrapping for your node. + +Once these steps are complete, AvalancheGo will be installed and configured, with default settings for running on the mainnet. + +```bash +Created symlink /etc/systemd/system/multi-user.target.wants/avalanchego.service → /etc/systemd/system/avalanchego.service. + +Done! + +Your node should now be bootstrapping. +Node configuration file is /home/subnet/.avalanchego/configs/node.json +C-Chain configuration file is /home/subnet/.avalanchego/configs/chains/C/config.json +Plugin directory, for storing subnet VM binaries, is /home/subnet/.avalanchego/plugins +To check that the service is running use the following command (q to exit): +sudo systemctl status avalanchego +To follow the log use (ctrl-c to stop): +sudo journalctl -u avalanchego -f +``` + +After installation, some configuration adjustments are needed. Navigate to the `~/.avalanchego/configs/node.json` file and make the following changes: + +```bash +{ + "http-host": "", + "public-ip-resolution-service": "opendns", + "network-id": "fuji", // Since we are working on Fuji testnet + "http-allowed-hosts": "*" // Allow all hosts or specify specific hosts for access +} + +``` + +## Installing AvalancheCli + +Now that AvalancheGo is set up, the next step is to install **Avalanche CLI**, which we’ll use to manage subnets and other network components. Proceed with the following steps to install Avalanche CLI. + +To install the Avalanche CLI, use the following command to download and run the installation script: + +```bash +curl -sSfL https://raw.githubusercontent.com/ava-labs/avalanche-cli/main/scripts/install.sh | sh -s +``` + +This will install **avalanche-cli** into your `~/bin` directory, automatically detecting your operating system and architecture. + +Adding CLI to PATH + +To make the CLI accessible from anywhere in the terminal, add `~/bin` to your `PATH` variable by running: + +```bash +export PATH=~/bin:$PATH +source ~/.bashrc # Reload the shell configuration + +``` + +After this, you should be able to use the Avalanche CLI by simply typing `avalanche` in the terminal. + +### Verifying Installation + +You can verify that the Avalanche CLI is installed and working by running `avalanche`: + +```bash +$ avalanche +Avalanche-CLI is a command-line tool that gives developers access to +everything Avalanche. This release specializes in helping developers +build and test Subnets. + +To get started, look at the documentation for the subcommands or jump right +in with avalanche subnet create myNewSubnet. + +Usage: + avalanche [command] + +Available Commands: + blockchain Create and deploy blockchains + config Modify configuration for Avalanche-CLI + contract Manage smart contracts + help Help about any command + ictt Manage Interchain Token Transferrers (shorthand for `interchain TokenTransferrer`) + interchain Set and manage interoperability between blockchains + key Create and manage testnet signing keys + network Manage locally deployed subnets + node Set up fuji and mainnet validator on cloud service + primary Interact with the Primary Network + subnet Create and deploy blockchains (deprecation notice: use 'avalanche blockchain') + teleporter Interact with teleporter-enabled subnets + transaction Sign and execute specific transactions + update Check for latest updates of Avalanche-CLI + +Flags: + --config string config file (default is $HOME/.avalanche-cli/config.json) + -h, --help help for avalanche + --log-level string log level for the application (default "ERROR") + --skip-update-check skip check for new versions + -v, --version version for avalanche + +Use "avalanche [command] --help" for more information about a command. +``` + +Now you're ready to start building your L1 using the Avalanche CLI! + +## Installing AWM Relayer + +To install the AWM Relayer, you can download it from the [AWM Relayer GitHub Releases](https://github.com/ava-labs/awm-relayer/releases/). If you’re using a Linux system with an AMD64 architecture, you can execute the following command: + +```bash +curl -s https://api.github.com/repos/ava-labs/awm-relayer/releases/latest | \ +grep "browser_download_url.*linux_amd64.tar.gz" | \ +cut -d '"' -f 4 | \ +xargs curl -LO && \ +mkdir -p /tmp/awm-relayer && \ +tar -xzf awm-relayer*_linux_amd64.tar.gz -C /tmp/awm-relayer && \ +mv /tmp/awm-relayer/awm-relayer ~/bin/ && \ +rm -rf /tmp/awm-relayer awm-relayer*_linux_amd64.tar.gz + +``` + +### Explanation + +- This command fetches the latest release of **AWM Relayer**, extracts it to a temporary directory, and moves it to `~/bin`. It then cleans up any leftover files. +- After running this, you should be able to access **AWM Relayer** by typing `awm-relayer` in your console. + +Creating a Systemd Service +For easier management, we’ll create a systemd service for the AWM Relayer. Open the service file in the nano: `sudo nano /etc/systemd/system/awm-relayer.service` +Then, add the following content to the file: + +```bash +[Unit] +Description=AWM Relayer Service +After=network.target + +[Service] +Type=simple +User=subnet +WorkingDirectory=/home/subnet +ExecStart=/home/subnet/bin/awm-relayer --config-file /home/subnet/.avalanchego/configs/relayer-config.json +LimitNOFILE=32768 +Restart=always +RestartSec=20 + +[Install] +WantedBy=multi-user.target +``` + +Next, you’ll need a configuration file for the relayer, which should be placed in `/.avalanchego/configs/`. Here’s an example of what your config file might look like: + +```json +{ + "info-api": { + "base-url": "http://127.0.0.1:9650" + }, + "p-chain-api": { + "base-url": "http://127.0.0.1:9650" + }, + "source-blockchains": [ + { + "subnet-id": "11111111111111111111111111111111LpoYY", + "blockchain-id": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "vm": "evm", + "rpc-endpoint": { + "base-url": "https://api.avax-test.network/ext/bc/C/rpc" + }, + "ws-endpoint": { + "base-url": "wss://avalanche-fuji-c-chain-rpc.publicnode.com" + }, + "message-contracts": { + "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf": { + "message-format": "teleporter", + "settings": { + "reward-address": "0x4b35a62D54FAda8F936eA817657839c6bF8f6bDc" + } + } + } + }, + { + "subnet-id": "Q8gj597wEjtArFsSLhc8MKCsFLiph8wKDPsVu52K6VPEhGV4R", + "blockchain-id": "TarZMhzx3WdEpJK6mBHwHCd3Wm1qnPecnv2ZRmEnh63Eg9sCc", + "vm": "evm", + "rpc-endpoint": { + "base-url": "http://127.0.0.1:9650/ext/bc/TarZMhzx3WdEpJK6mBHwHCd3Wm1qnPecnv2ZRmEnh63Eg9sCc/rpc" + }, + "ws-endpoint": { + "base-url": "ws://127.0.0.1:9650/ext/bc/TarZMhzx3WdEpJK6mBHwHCd3Wm1qnPecnv2ZRmEnh63Eg9sCc/ws" + }, + "message-contracts": { + "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf": { + "message-format": "teleporter", + "settings": { + "reward-address": "0x03FDA0059a1c7fA25d17e0beB041e3Dfe1E25D09" + } + } + } + } + ], + "destination-blockchains": [ + { + "subnet-id": "Q8gj597wEjtArFsSLhc8MKCsFLiph8wKDPsVu52K6VPEhGV4R", + "blockchain-id": "TarZMhzx3WdEpJK6mBHwHCd3Wm1qnPecnv2ZRmEnh63Eg9sCc", + "vm": "evm", + "rpc-endpoint": { + "base-url": "http://127.0.0.1:9650/ext/bc/TarZMhzx3WdEpJK6mBHwHCd3Wm1qnPecnv2ZRmEnh63Eg9sCc/rpc" + }, + "account-private-key": "0x123d6a..." + }, + { + "subnet-id": "11111111111111111111111111111111LpoYY", + "blockchain-id": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", + "vm": "evm", + "rpc-endpoint": { + "base-url": "https://api.avax-test.network/ext/bc/C/rpc" + }, + "account-private-key": "0x123d6a..." + } + ] +} +``` + +For more options, you can refer to [this link](https://academy.avax.network/course/interchain-messaging/10-running-a-relayer/04-relayer-configuration). + +### Final Steps + +1. **Start the Service**: After creating the service and the config file, enable and start the service with: + + ```bash + sudo systemctl enable awm-relayer #To start on boot + sudo systemctl start awm-relayer + ``` + +2. **Check Service Status**: You can verify that the service is running with: + + ```bash + sudo systemctl status awm-relayer + ``` + + +# Setting Up Validators for Your L1 Network + +To fully operationalize your L1 network, you need to set up validators that will secure and maintain it. Here’s a step-by-step guide to becoming a validator on the Fuji Testnet. + +### Requirements for Becoming a Validator + +1. **P-Chain Balance**: Ensure that you have at least 1 AVAX transferred to the P-Chain. You can transfer AVAX using the following link: [Fuji Testnet Cross-Chain Transfer](https://test.core.app/stake/cross-chain-transfer/). +2. **Gather Information**: When adding your node to the validator set, you will need to provide the following details: + - **Node ID**: Your node’s unique identifier. + - **BLS Key and Signature**: The BLS key pair for your node. + - **Start and Stop Times**: Specify when you want to start and stop validating. + - **Staking Amount**: The amount of AVAX you wish to stake (minimum of 1 AVAX). + - **Reward Address**: The address to which any rewards will be sent. + - **Delegation Fee Rate**: The fee rate you will charge for delegating. + +### Staking Parameters on Fuji Testnet + +- **Minimum Stake**: 1 AVAX +- **Minimum Staking Duration**: 24 hours + +Transfer C-Chain AVAX to P-Chain + +![image.png](images/image.png) + +Stake at least 1 AVAX + +![image.png](images/image%201.png) + +Get your nodeId with curl + +![image.png](images/image%202.png) + +Fill in your NodeID and BLS Key-Signature + +![image.png](images/image%203.png) + +Select stake duration + +![image.png](images/image%204.png) + +Choose your reward address + +![image.png](images/image%205.png) + +Enter your delegation fee + +![image.png](images/image%206.png) + +Check your information and submit + +![image.png](images/image%207.png) + +Now you are set up as a validator. + +![image.png](images/image%208.png) + +# Creating Configuration + +To create a custom blockchain configuration using Avalanche CLI, you can follow the step-by-step process outlined below, which generates the `genesis.json` file for your Layer 1 (L1) blockchain and allows you to customize key aspects such as token allocation, transaction fees, and interoperability with other blockchains. + +Step-by-Step Configuration + +1. **Create a L1**:Start by using the following command to create a blockchain configuration: + + ```bash + avalanche blockchain create ATTOS + ``` + +2. **Choose Virtual Machine**:Use the arrow keys to select the **Subnet-EVM** option, which is suitable for Ethereum Virtual Machine (EVM)-based networks. + + ```bash + 1-? Which Virtual Machine would you like to use?: + ▸ Subnet-EVM + ``` + +3. **Select Environment**:Choose **I don’t want to use default values** to fully customize your configuration. + + ```bash + 2-? Do you want to use default values for the Blockchain configuration?: + ▸ I don't want to use default values + + ``` + +4. **Select Latest Version**:Use the latest version unless you have specific needs for a custom version. + + ```bash + 3-? Version: + ▸ Use latest release version + ``` + +5. **Set Chain ID**:Set the **Chain ID**. You can use a custom ID `1304` +6. **Token Symbol**:Enter the **Token Symbol** (e.g., USDC since we are building a payments system with USDC). + + ```bash + 5-? Token Symbol: USDC + ``` + +7. **Token Allocation**:Choose **Define a custom allocation** and specify your address and allocation amount. + + ```bash + 6-? How should the initial token allocation be structured?: + ▸ Define a custom allocation (Recommended for production) + + 7-? Address to allocate to: 0xEB7F53799cE1FfD0Ac62D91Cc6E1473D8C9BdF68 + 8-? Amount to allocate (in USDC units): 10 #These tokens must be colaterized later + ``` + +8. **Enable Minting**:Choose **Yes** to allow minting additional native tokens. This will turn on the Native Minter Precompile. + + ```bash + 9-? Allow minting of new native tokens?: + ▸ Yes, I want to be able to mint additional native tokens (Native Minter Precompile ON) + ``` + +9. **Add Admin Role**:Specify your wallet address with **Admin** permissions in the allow list. + + ```bash + 10-? Configure the addresses that are allowed to mint native tokens: + ▸ Add an address for a role to the allow list + + 11-? What role should the address have?: + ▸ Admin + + 12-? Enter the address of the account: 0x4ccA41E9Becd40De40b7b0B96c58070c4a580f82 #Put your own address + ``` + +10. **Transaction Fees**:Choose **Medium block size** and enable **dynamic fees** for flexibility. + + ```bash + 15-? How should the transaction fees be configured?: + ▸ Medium block size / Medium Throughput 15 mil gas per block (C-Chain's setting) + + 16-? Do you want dynamic fees on your blockchain?: + ▸ Yes, I would like my blockchain to have dynamic fees + ``` + +11. **Burning Transaction Fees**:Choose to burn transaction fees by default. + + ```bash + 18-? Do you want the transaction fees to be burned?: + ▸ Yes, I want the transaction fees to be burned + ``` + +12. **Enable Interoperability**:Enable the blockchain to interoperate with other blockchains and the C-Chain. + + ```bash + 19-? Do you want to connect your blockchain with other blockchains or the C-Chain?: + ▸ Yes + ``` + +13. **Allow Transactions and Contracts**:Allow anyone to issue transactions and deploy smart contracts. + + ```bash + 20-? Do you want to enable anyone to issue transactions and deploy smart contracts to your blockchain?: + ▸ Yes + ``` + + +## Genesis File Location + +Once you finish these steps, the `genesis.json` file is generated in the following directory: + +```bash +/home/[your username]/.avalanche-cli/subnets/ATTOS/genesis.json +``` + +### Teleporter Contract Integration + +To enable communication with other L1 blockchains and the C-chain, include the **teleporter contract address** in the `genesis.json` file. Add this configuration under the relevant sections to ensure your blockchain can use the teleporter for interoperability. + +```jsx +"alloc": { + "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b506004361061014d5760003560e01c8063a8898181116100c3578063df20e8bc1161007c578063df20e8bc1461033b578063e69d606a1461034e578063e6e67bd5146103b6578063ebc3b1ba146103f2578063ecc7042814610415578063fc2d61971461041e57600080fd5b8063a8898181146102b2578063a9a85614146102c5578063b771b3bc146102d8578063c473eef8146102e6578063ccb5f8091461031f578063d127dc9b1461033257600080fd5b8063399b77da11610115578063399b77da1461021957806362448850146102395780638245a1b01461024c578063860a3b061461025f578063892bf4121461027f5780638ac0fd041461029f57600080fd5b80630af5b4ff1461015257806322296c3a1461016d5780632bc8b0bf146101825780632ca40f55146101955780632e27c223146101ee575b600080fd5b61015a610431565b6040519081526020015b60405180910390f35b61018061017b366004612251565b610503565b005b61015a61019036600461226e565b6105f8565b6101e06101a336600461226e565b6005602090815260009182526040918290208054835180850190945260018201546001600160a01b03168452600290910154918301919091529082565b604051610164929190612287565b6102016101fc36600461226e565b610615565b6040516001600160a01b039091168152602001610164565b61015a61022736600461226e565b60009081526005602052604090205490565b61015a6102473660046122ae565b61069e565b61018061025a366004612301565b6106fc565b61015a61026d36600461226e565b60066020526000908152604090205481565b61029261028d366004612335565b6108a7565b6040516101649190612357565b6101806102ad366004612377565b6108da565b61015a6102c03660046123af565b610b19565b61015a6102d3366004612426565b610b5c565b6102016005600160991b0181565b61015a6102f43660046124be565b6001600160a01b03918216600090815260096020908152604080832093909416825291909152205490565b61018061032d3660046124f7565b610e03565b61015a60025481565b61015a61034936600461226e565b61123d565b61039761035c36600461226e565b600090815260056020908152604091829020825180840190935260018101546001600160a01b03168084526002909101549290910182905291565b604080516001600160a01b039093168352602083019190915201610164565b6103dd6103c436600461226e565b6004602052600090815260409020805460019091015482565b60408051928352602083019190915201610164565b61040561040036600461226e565b611286565b6040519015158152602001610164565b61015a60035481565b61018061042c36600461251e565b61129c565b600254600090806104fe576005600160991b016001600160a01b0316634213cf786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a59190612564565b9050806104cd5760405162461bcd60e51b81526004016104c49061257d565b60405180910390fd5b600281905560405181907f1eac640109dc937d2a9f42735a05f794b39a5e3759d681951d671aabbce4b10490600090a25b919050565b3360009081526009602090815260408083206001600160a01b0385168452909152902054806105855760405162461bcd60e51b815260206004820152602860248201527f54656c65706f727465724d657373656e6765723a206e6f2072657761726420746044820152676f2072656465656d60c01b60648201526084016104c4565b3360008181526009602090815260408083206001600160a01b03871680855290835281842093909355518481529192917f3294c84e5b0f29d9803655319087207bc94f4db29f7927846944822773780b88910160405180910390a36105f46001600160a01b03831633836114f7565b5050565b600081815260046020526040812061060f9061155f565b92915050565b6000818152600760205260408120546106825760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a206d657373616765206e6f74604482015268081c9958d95a5d995960ba1b60648201526084016104c4565b506000908152600860205260409020546001600160a01b031690565b60006001600054146106c25760405162461bcd60e51b81526004016104c4906125c4565b60026000556106f16106d383612804565b833560009081526004602052604090206106ec90611572565b61167c565b600160005592915050565b60016000541461071e5760405162461bcd60e51b81526004016104c4906125c4565b6002600081815590546107379060408401358435610b19565b6000818152600560209081526040918290208251808401845281548152835180850190945260018201546001600160a01b03168452600290910154838301529081019190915280519192509061079f5760405162461bcd60e51b81526004016104c4906128a7565b6000836040516020016107b29190612b42565b60408051601f19818403018152919052825181516020830120919250146107eb5760405162461bcd60e51b81526004016104c490612b55565b8360400135837f2a211ad4a59ab9d003852404f9c57c690704ee755f3c79d2c2812ad32da99df8868560200151604051610826929190612b9e565b60405180910390a360405163ee5b48eb60e01b81526005600160991b019063ee5b48eb90610858908490600401612c23565b6020604051808303816000875af1158015610877573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089b9190612564565b50506001600055505050565b604080518082019091526000808252602082015260008381526004602052604090206108d390836118bc565b9392505050565b6001600054146108fc5760405162461bcd60e51b81526004016104c4906125c4565b600260005560018054146109225760405162461bcd60e51b81526004016104c490612c36565b60026001558061098c5760405162461bcd60e51b815260206004820152602f60248201527f54656c65706f727465724d657373656e6765723a207a65726f2061646469746960448201526e1bdb985b0819995948185b5bdd5b9d608a1b60648201526084016104c4565b6001600160a01b0382166109b25760405162461bcd60e51b81526004016104c490612c7b565b6000838152600560205260409020546109dd5760405162461bcd60e51b81526004016104c4906128a7565b6000838152600560205260409020600101546001600160a01b03838116911614610a6f5760405162461bcd60e51b815260206004820152603760248201527f54656c65706f727465724d657373656e6765723a20696e76616c69642066656560448201527f20617373657420636f6e7472616374206164647265737300000000000000000060648201526084016104c4565b6000610a7b8383611981565b600085815260056020526040812060020180549293508392909190610aa1908490612ce5565b909155505060008481526005602052604090819020905185917fc1bfd1f1208927dfbd414041dcb5256e6c9ad90dd61aec3249facbd34ff7b3e191610b03916001019081546001600160a01b0316815260019190910154602082015260400190565b60405180910390a2505060018080556000555050565b60408051306020820152908101849052606081018390526080810182905260009060a0016040516020818303038152906040528051906020012090509392505050565b6000600160005414610b805760405162461bcd60e51b81526004016104c4906125c4565b60026000818155905490866001600160401b03811115610ba257610ba2612607565b604051908082528060200260200182016040528015610be757816020015b6040805180820190915260008082526020820152815260200190600190039081610bc05790505b5090508660005b81811015610d6c5760008a8a83818110610c0a57610c0a612cf8565b90506020020135905060006007600083815260200190815260200160002054905080600003610c8a5760405162461bcd60e51b815260206004820152602660248201527f54656c65706f727465724d657373656e6765723a2072656365697074206e6f7460448201526508199bdd5b9960d21b60648201526084016104c4565b610c958d8783610b19565b8214610d095760405162461bcd60e51b815260206004820152603a60248201527f54656c65706f727465724d657373656e6765723a206d6573736167652049442060448201527f6e6f742066726f6d20736f7572636520626c6f636b636861696e00000000000060648201526084016104c4565b6000828152600860209081526040918290205482518084019093528383526001600160a01b03169082018190528651909190879086908110610d4d57610d4d612cf8565b602002602001018190525050505080610d6590612d0e565b9050610bee565b506040805160c0810182528b815260006020820152610df0918101610d96368b90038b018b612d27565b8152602001600081526020018888808060200260200160405190810160405280939291908181526020018383602002808284376000920182905250938552505060408051928352602080840190915290920152508361167c565b60016000559a9950505050505050505050565b6001805414610e245760405162461bcd60e51b81526004016104c490612c36565b60026001556040516306f8253560e41b815263ffffffff8316600482015260009081906005600160991b0190636f82535090602401600060405180830381865afa158015610e76573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e9e9190810190612da3565b9150915080610f015760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a20696e76616c69642077617260448201526870206d65737361676560b81b60648201526084016104c4565b60208201516001600160a01b03163014610f785760405162461bcd60e51b815260206004820152603260248201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206f726960448201527167696e2073656e646572206164647265737360701b60648201526084016104c4565b60008260400151806020019051810190610f929190612f40565b90506000610f9e610431565b90508082604001511461100d5760405162461bcd60e51b815260206004820152603160248201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206465736044820152701d1a5b985d1a5bdb8818da185a5b881251607a1b60648201526084016104c4565b8351825160009161101f918490610b19565b600081815260076020526040902054909150156110945760405162461bcd60e51b815260206004820152602d60248201527f54656c65706f727465724d657373656e6765723a206d65737361676520616c7260448201526c1958591e481c9958d95a5d9959609a1b60648201526084016104c4565b6110a2338460a00151611ae9565b6111005760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a20756e617574686f72697a6560448201526832103932b630bcb2b960b91b60648201526084016104c4565b61110e818460000151611b61565b6001600160a01b0386161561114557600081815260086020526040902080546001600160a01b0319166001600160a01b0388161790555b60c08301515160005b81811015611192576111828488600001518760c00151848151811061117557611175612cf8565b6020026020010151611bd3565b61118b81612d0e565b905061114e565b50604080518082018252855181526001600160a01b038916602080830191909152885160009081526004909152919091206111cc91611cfb565b336001600160a01b03168660000151837f292ee90bbaf70b5d4936025e09d56ba08f3e421156b6a568cf3c2840d9343e348a8860405161120d929190613150565b60405180910390a460e0840151511561122f5761122f82876000015186611d57565b505060018055505050505050565b600254600090806112605760405162461bcd60e51b81526004016104c49061257d565b600060035460016112719190612ce5565b905061127e828583610b19565b949350505050565b600081815260076020526040812054151561060f565b60018054146112bd5760405162461bcd60e51b81526004016104c490612c36565b60026001819055546000906112d59084908435610b19565b600081815260066020526040902054909150806113045760405162461bcd60e51b81526004016104c4906128a7565b80836040516020016113169190612b42565b60405160208183030381529060405280519060200120146113495760405162461bcd60e51b81526004016104c490612b55565b600061135b6080850160608601612251565b6001600160a01b03163b116113cf5760405162461bcd60e51b815260206004820152603460248201527f54656c65706f727465724d657373656e6765723a2064657374696e6174696f6e604482015273206164647265737320686173206e6f20636f646560601b60648201526084016104c4565b604051849083907f34795cc6b122b9a0ae684946319f1e14a577b4e8f9b3dda9ac94c21a54d3188c90600090a360008281526006602090815260408083208390558691611420918701908701612251565b61142d60e0870187613174565b60405160240161144094939291906131ba565b60408051601f198184030181529190526020810180516001600160e01b031663643477d560e11b179052905060006114886114816080870160608801612251565b5a84611e8a565b9050806114eb5760405162461bcd60e51b815260206004820152602b60248201527f54656c65706f727465724d657373656e6765723a20726574727920657865637560448201526a1d1a5bdb8819985a5b195960aa1b60648201526084016104c4565b50506001805550505050565b6040516001600160a01b03831660248201526044810182905261155a90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611ea4565b505050565b8054600182015460009161060f916131e5565b6060600061158960056115848561155f565b611f76565b9050806000036115d85760408051600080825260208201909252906115d0565b60408051808201909152600080825260208201528152602001906001900390816115a95790505b509392505050565b6000816001600160401b038111156115f2576115f2612607565b60405190808252806020026020018201604052801561163757816020015b60408051808201909152600080825260208201528152602001906001900390816116105790505b50905060005b828110156115d05761164e85611f8c565b82828151811061166057611660612cf8565b60200260200101819052508061167590612d0e565b905061163d565b600080611687610431565b9050600060036000815461169a90612d0e565b919050819055905060006116b383876000015184610b19565b90506000604051806101000160405280848152602001336001600160a01b031681526020018860000151815260200188602001516001600160a01b0316815260200188606001518152602001886080015181526020018781526020018860a00151815250905060008160405160200161172c91906131f8565b60405160208183030381529060405290506000808960400151602001511115611794576040890151516001600160a01b031661177a5760405162461bcd60e51b81526004016104c490612c7b565b604089015180516020909101516117919190611981565b90505b6040805180820182528a820151516001600160a01b039081168252602080830185905283518085018552865187830120815280820184815260008a815260058452869020915182555180516001830180546001600160a01b03191691909516179093559101516002909101558a51915190919086907f2a211ad4a59ab9d003852404f9c57c690704ee755f3c79d2c2812ad32da99df890611838908890869061320b565b60405180910390a360405163ee5b48eb60e01b81526005600160991b019063ee5b48eb9061186a908690600401612c23565b6020604051808303816000875af1158015611889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ad9190612564565b50939998505050505050505050565b60408051808201909152600080825260208201526118d98361155f565b82106119315760405162461bcd60e51b815260206004820152602160248201527f5265636569707451756575653a20696e646578206f7574206f6620626f756e646044820152607360f81b60648201526084016104c4565b8260020160008385600001546119479190612ce5565b81526020808201929092526040908101600020815180830190925280548252600101546001600160a01b0316918101919091529392505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b038516906370a0823190602401602060405180830381865afa1580156119ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ee9190612564565b9050611a056001600160a01b038516333086612058565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa158015611a4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a709190612564565b9050818111611ad65760405162461bcd60e51b815260206004820152602c60248201527f5361666545524332305472616e7366657246726f6d3a2062616c616e6365206e60448201526b1bdd081a5b98dc99585cd95960a21b60648201526084016104c4565b611ae082826131e5565b95945050505050565b60008151600003611afc5750600161060f565b815160005b81811015611b5657846001600160a01b0316848281518110611b2557611b25612cf8565b60200260200101516001600160a01b031603611b465760019250505061060f565b611b4f81612d0e565b9050611b01565b506000949350505050565b80600003611bc15760405162461bcd60e51b815260206004820152602760248201527f54656c65706f727465724d657373656e6765723a207a65726f206d657373616760448201526665206e6f6e636560c81b60648201526084016104c4565b60009182526007602052604090912055565b6000611be484848460000151610b19565b6000818152600560209081526040918290208251808401845281548152835180850190945260018201546001600160a01b031684526002909101548383015290810191909152805191925090611c3b575050505050565b60008281526005602090815260408083208381556001810180546001600160a01b03191690556002018390558382018051830151878401516001600160a01b0390811686526009855283862092515116855292528220805491929091611ca2908490612ce5565b9250508190555082602001516001600160a01b031684837fd13a7935f29af029349bed0a2097455b91fd06190a30478c575db3f31e00bf578460200151604051611cec919061321e565b60405180910390a45050505050565b6001820180548291600285019160009182611d1583612d0e565b90915550815260208082019290925260400160002082518155910151600190910180546001600160a01b0319166001600160a01b039092169190911790555050565b80608001515a1015611db95760405162461bcd60e51b815260206004820152602560248201527f54656c65706f727465724d657373656e6765723a20696e73756666696369656e604482015264742067617360d81b60648201526084016104c4565b80606001516001600160a01b03163b600003611dda5761155a838383612096565b602081015160e0820151604051600092611df892869260240161323e565b60408051601f198184030181529190526020810180516001600160e01b031663643477d560e11b17905260608301516080840151919250600091611e3d919084611e8a565b905080611e5657611e4f858585612096565b5050505050565b604051849086907f34795cc6b122b9a0ae684946319f1e14a577b4e8f9b3dda9ac94c21a54d3188c90600090a35050505050565b60008060008084516020860160008989f195945050505050565b6000611ef9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661210b9092919063ffffffff16565b80519091501561155a5780806020019051810190611f179190613268565b61155a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104c4565b6000818310611f8557816108d3565b5090919050565b604080518082019091526000808252602082015281546001830154819003611ff65760405162461bcd60e51b815260206004820152601960248201527f5265636569707451756575653a20656d7074792071756575650000000000000060448201526064016104c4565b60008181526002840160208181526040808420815180830190925280548252600180820180546001600160a01b03811685870152888852959094529490556001600160a01b031990921690559061204e908390612ce5565b9093555090919050565b6040516001600160a01b03808516602483015283166044820152606481018290526120909085906323b872dd60e01b90608401611523565b50505050565b806040516020016120a791906131f8565b60408051601f1981840301815282825280516020918201206000878152600690925291902055829084907f4619adc1017b82e02eaefac01a43d50d6d8de4460774bc370c3ff0210d40c985906120fe9085906131f8565b60405180910390a3505050565b606061127e848460008585600080866001600160a01b031685876040516121329190613283565b60006040518083038185875af1925050503d806000811461216f576040519150601f19603f3d011682016040523d82523d6000602084013e612174565b606091505b509150915061218587838387612190565b979650505050505050565b606083156121ff5782516000036121f8576001600160a01b0385163b6121f85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104c4565b508161127e565b61127e83838151156122145781518083602001fd5b8060405162461bcd60e51b81526004016104c49190612c23565b6001600160a01b038116811461224357600080fd5b50565b80356104fe8161222e565b60006020828403121561226357600080fd5b81356108d38161222e565b60006020828403121561228057600080fd5b5035919050565b828152606081016108d3602083018480516001600160a01b03168252602090810151910152565b6000602082840312156122c057600080fd5b81356001600160401b038111156122d657600080fd5b820160e081850312156108d357600080fd5b600061010082840312156122fb57600080fd5b50919050565b60006020828403121561231357600080fd5b81356001600160401b0381111561232957600080fd5b61127e848285016122e8565b6000806040838503121561234857600080fd5b50508035926020909101359150565b815181526020808301516001600160a01b0316908201526040810161060f565b60008060006060848603121561238c57600080fd5b83359250602084013561239e8161222e565b929592945050506040919091013590565b6000806000606084860312156123c457600080fd5b505081359360208301359350604090920135919050565b60008083601f8401126123ed57600080fd5b5081356001600160401b0381111561240457600080fd5b6020830191508360208260051b850101111561241f57600080fd5b9250929050565b60008060008060008086880360a081121561244057600080fd5b8735965060208801356001600160401b038082111561245e57600080fd5b61246a8b838c016123db565b90985096508691506040603f198401121561248457600080fd5b60408a01955060808a013592508083111561249e57600080fd5b50506124ac89828a016123db565b979a9699509497509295939492505050565b600080604083850312156124d157600080fd5b82356124dc8161222e565b915060208301356124ec8161222e565b809150509250929050565b6000806040838503121561250a57600080fd5b823563ffffffff811681146124dc57600080fd5b6000806040838503121561253157600080fd5b8235915060208301356001600160401b0381111561254e57600080fd5b61255a858286016122e8565b9150509250929050565b60006020828403121561257657600080fd5b5051919050565b60208082526027908201527f54656c65706f727465724d657373656e6765723a207a65726f20626c6f636b636040820152661a185a5b88125160ca1b606082015260800190565b60208082526023908201527f5265656e7472616e63794775617264733a2073656e646572207265656e7472616040820152626e637960e81b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561263f5761263f612607565b60405290565b60405160c081016001600160401b038111828210171561263f5761263f612607565b60405161010081016001600160401b038111828210171561263f5761263f612607565b604051601f8201601f191681016001600160401b03811182821017156126b2576126b2612607565b604052919050565b6000604082840312156126cc57600080fd5b6126d461261d565b905081356126e18161222e565b808252506020820135602082015292915050565b60006001600160401b0382111561270e5761270e612607565b5060051b60200190565b600082601f83011261272957600080fd5b8135602061273e612739836126f5565b61268a565b82815260059290921b8401810191818101908684111561275d57600080fd5b8286015b848110156127815780356127748161222e565b8352918301918301612761565b509695505050505050565b60006001600160401b038211156127a5576127a5612607565b50601f01601f191660200190565b600082601f8301126127c457600080fd5b81356127d26127398261278c565b8181528460208386010111156127e757600080fd5b816020850160208301376000918101602001919091529392505050565b600060e0823603121561281657600080fd5b61281e612645565b8235815261282e60208401612246565b602082015261284036604085016126ba565b60408201526080830135606082015260a08301356001600160401b038082111561286957600080fd5b61287536838701612718565b608084015260c085013591508082111561288e57600080fd5b5061289b368286016127b3565b60a08301525092915050565b60208082526026908201527f54656c65706f727465724d657373656e6765723a206d657373616765206e6f7460408201526508199bdd5b9960d21b606082015260800190565b6000808335601e1984360301811261290457600080fd5b83016020810192503590506001600160401b0381111561292357600080fd5b8060051b360382131561241f57600080fd5b8183526000602080850194508260005b858110156129735781356129588161222e565b6001600160a01b031687529582019590820190600101612945565b509495945050505050565b6000808335601e1984360301811261299557600080fd5b83016020810192503590506001600160401b038111156129b457600080fd5b8060061b360382131561241f57600080fd5b8183526000602080850194508260005b858110156129735781358752828201356129ef8161222e565b6001600160a01b03168784015260409687019691909101906001016129d6565b6000808335601e19843603018112612a2657600080fd5b83016020810192503590506001600160401b03811115612a4557600080fd5b80360382131561241f57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000610100823584526020830135612a948161222e565b6001600160a01b0316602085015260408381013590850152612ab860608401612246565b6001600160a01b0316606085015260808381013590850152612add60a08401846128ed565b8260a0870152612af08387018284612935565b92505050612b0160c084018461297e565b85830360c0870152612b148382846129c6565b92505050612b2560e0840184612a0f565b85830360e0870152612b38838284612a54565b9695505050505050565b6020815260006108d36020830184612a7d565b60208082526029908201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206d65736040820152680e6c2ceca40d0c2e6d60bb1b606082015260800190565b606081526000612bb16060830185612a7d565b90506108d3602083018480516001600160a01b03168252602090810151910152565b60005b83811015612bee578181015183820152602001612bd6565b50506000910152565b60008151808452612c0f816020860160208601612bd3565b601f01601f19169290920160200192915050565b6020815260006108d36020830184612bf7565b60208082526025908201527f5265656e7472616e63794775617264733a207265636569766572207265656e7460408201526472616e637960d81b606082015260800190565b60208082526034908201527f54656c65706f727465724d657373656e6765723a207a65726f2066656520617360408201527373657420636f6e7472616374206164647265737360601b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561060f5761060f612ccf565b634e487b7160e01b600052603260045260246000fd5b600060018201612d2057612d20612ccf565b5060010190565b600060408284031215612d3957600080fd5b6108d383836126ba565b80516104fe8161222e565b600082601f830112612d5f57600080fd5b8151612d6d6127398261278c565b818152846020838601011115612d8257600080fd5b61127e826020830160208701612bd3565b805180151581146104fe57600080fd5b60008060408385031215612db657600080fd5b82516001600160401b0380821115612dcd57600080fd5b9084019060608287031215612de157600080fd5b604051606081018181108382111715612dfc57612dfc612607565b604052825181526020830151612e118161222e565b6020820152604083015182811115612e2857600080fd5b612e3488828601612d4e565b6040830152509350612e4b91505060208401612d93565b90509250929050565b600082601f830112612e6557600080fd5b81516020612e75612739836126f5565b82815260059290921b84018101918181019086841115612e9457600080fd5b8286015b84811015612781578051612eab8161222e565b8352918301918301612e98565b600082601f830112612ec957600080fd5b81516020612ed9612739836126f5565b82815260069290921b84018101918181019086841115612ef857600080fd5b8286015b848110156127815760408189031215612f155760008081fd5b612f1d61261d565b8151815284820151612f2e8161222e565b81860152835291830191604001612efc565b600060208284031215612f5257600080fd5b81516001600160401b0380821115612f6957600080fd5b908301906101008286031215612f7e57600080fd5b612f86612667565b82518152612f9660208401612d43565b602082015260408301516040820152612fb160608401612d43565b60608201526080830151608082015260a083015182811115612fd257600080fd5b612fde87828601612e54565b60a08301525060c083015182811115612ff657600080fd5b61300287828601612eb8565b60c08301525060e08301518281111561301a57600080fd5b61302687828601612d4e565b60e08301525095945050505050565b600081518084526020808501945080840160005b838110156129735781516001600160a01b031687529582019590820190600101613049565b600081518084526020808501945080840160005b83811015612973576130a8878351805182526020908101516001600160a01b0316910152565b6040969096019590820190600101613082565b60006101008251845260018060a01b0360208401511660208501526040830151604085015260608301516130fa60608601826001600160a01b03169052565b506080830151608085015260a08301518160a086015261311c82860182613035565b91505060c083015184820360c0860152613136828261306e565b91505060e083015184820360e0860152611ae08282612bf7565b6001600160a01b038316815260406020820181905260009061127e908301846130bb565b6000808335601e1984360301811261318b57600080fd5b8301803591506001600160401b038211156131a557600080fd5b60200191503681900382131561241f57600080fd5b8481526001600160a01b0384166020820152606060408201819052600090612b389083018486612a54565b8181038181111561060f5761060f612ccf565b6020815260006108d360208301846130bb565b606081526000612bb160608301856130bb565b81516001600160a01b03168152602080830151908201526040810161060f565b8381526001600160a01b0383166020820152606060408201819052600090611ae090830184612bf7565b60006020828403121561327a57600080fd5b6108d382612d93565b60008251613295818460208701612bd3565b919091019291505056fea2646970667358221220586881dd1413fe17197100ceb55646481dae802ef65d37df603c3915f51a4b6364736f6c63430008120033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "nonce": 1 + }, + "0x618FEdD9A45a8C456812ecAAE70C671c6249DfaC": { + "balance": "0x0", + "nonce": 1 + } +} +``` + +# Deploying L1 to Fuji Testnet + +```bash +$ avalanche blockchain deploy ATTOS +``` + +- **Choose a network**: Select **Fuji Testnet**. +- **Transaction fee payment**: Choose **Use stored key**. +- **Select key**: Pick the funded address ,on our case **admin**. +- **Configure control keys**: Choose **Use fee-paying key** to set it as the control key. + +after that you should see something like this + +![image.png](images/image%209.png) + +Since we are now a validator with a running node, we can proceed to add our node to the blockchain. + +### Adding a Validator to the Avalanche Blockchain + +To add a validator for the **ATTOS** blockchain on the **Fuji Testnet**, run the following command: + +```bash +$ avalanche blockchain addValidator ATTOS +``` + +- **Network**: Fuji Testnet +- **Key Source**: Use stored key +- **Selected Key**: admin + +Next, we need the **NodeID** of the validator you want to whitelist. + +- **Validator NodeID**: `NodeID-7Uk7qftSLFvvhvXnZR7TDDPRA5grvuRqK` +- **Stake Weight**: Default (20) + +### Validator Start Time + +If your validator is not ready by this time, subnet downtime may occur. + +- **Start Time**: Start in 5 minutes +- **Validation Duration**: Until primary network validator expires + +### Summary of Inputs + +- **NodeID**: `NodeID-7Uk7qftSLFvvhvXnZR7TDDPRA5grvuRqK` +- **Network**: Fuji +- **Start Time**: 2024-09-28 11:30:23 +- **End Time**: 2025-09-28 11:20:59 +- **Weight**: 20 + +All inputs are complete; issuing transaction to add the provided validator information. + +Now, we've completed the installation and configuration process. + +# Deploying Contracts for Cross-Chain Transactions + +First lets define our variables + +```bash +export C_CHAIN_BLOCKCHAIN_ID_HEX=0x7fc93d85c6d62c5b2ac0b519c87010ea5294012d1e407030d6acd0021cac10d5 +export L1_BLOCKCHAIN_ID_HEX=0x3c5c8.... #Your L1 blockchainId +export TELEPORTER_REGISTRY_C_CHAIN=0xF86Cb19Ad8405AEFa7d09C778215D2Cb6eBfB228 #On Fuji +export TELEPORTER_MESSENGER=0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf #On all networks +export L1RPC=http://[L1 rpc]/rpc # Your L1 rpc +export CRPC=http://[C rpc]/C/rpc #C rpc +export USDC_TOKEN_ADDRESS=0x5425890298aed601595a70AB815c96711a31Bc65 #Circle USDC +export PVK=cf75c.... +export myAddress=0x4cc... +``` + +![image.png](images/image%2010.png) + +Teleporter addresses.Can also be found at [Teleporter repo](https://github.com/ava-labs/teleporter?tab=readme-ov-file#deployed-addresses) + +To manage cross-chain transactions securely and efficiently, we need to deploy two contracts: **Token Home** and **Token Remote**. + +### 1. **Token Home Contract** + +- **Purpose**: Deployed on the source chain (e.g., Avalanche), it manages the original token, locking or burning it when transferring assets to another chain. This ensures controlled supply and prevents duplication. + +### 2. **Token Remote Contract** + +- **Purpose**: Deployed on the destination chain, it mints or releases corresponding tokens to the recipient after confirmation from the Token Home contract. This maintains token integrity across chains. + +### Deployment Overview + +To integrate **USDC** into your setup on the **Fuji Testnet**, you don’t need to deploy an ERC-20 token, as USDC is already available. However, we will deploy an `ERC20Home` contract. + +### ERC20Home Contract Deployment + +```solidity +constructor( + address teleporterRegistryAddress, + address teleporterManager, + address tokenAddress_, + uint8 tokenDecimals_ +) TokenHome(teleporterRegistryAddress, teleporterManager, tokenAddress_, tokenDecimals_) { + token = IERC20(tokenAddress); +} +``` + +**Constructor Arguments**: + +- `teleporterRegistryAddress` +- `teleporterManager` (use admin address) +- `tokenAddress_` (address of USDC) +- `tokenDecimals_` (decimals for USDC, valued 6) + +**Deployment Command**: + +```bash +forge create --rpc-url $CRPC --private-key $PVK lib/avalanche-interchain-token-transfer/contracts/src/TokenHome/ERC20TokenHome.sol:ERC20TokenHome --constructor-args ${TELEPORTER_REGISTRY_C_CHAIN} ${myAddress} ${USDC_TOKEN_ADDRESS} 6 +export TOKEN_HOME=0x6a9bec39bbAbD6DEF835691deFb4451.... #This should be your deployed address + +``` + +3. **NativeTokenRemote Contract Deployment** + +Contract Structure + +```solidity +struct TokenRemoteSettings { + address teleporterRegistryAddress; + address teleporterManager; + bytes32 tokenHomeBlockchainID; + address tokenHomeAddress; + uint8 tokenHomeDecimals; +} +constructor( + TokenRemoteSettings memory settings, + string memory nativeAssetSymbol, + uint256 initialReserveImbalance, + uint256 burnedFeesReportingRewardPercentage_ +) ERC20(string.concat("Wrapped ", nativeAssetSymbol), nativeAssetSymbol) TokenRemote(settings, initialReserveImbalance, 18) { + require(initialReserveImbalance != 0, "NativeTokenRemote: zero initial reserve imbalance"); + require(burnedFeesReportingRewardPercentage_ < 100, "NativeTokenRemote: invalid percentage"); + burnedFeesReportingRewardPercentage = burnedFeesReportingRewardPercentage_; +} +``` + +**Constructor Arguments**: + +- `TokenRemoteSettings` (with the required fields) +- `nativeAssetSymbol` (e.g., USDC) +- `initialReserveImbalance` (e.g., 10000000) initilized amount +- `burnedFeesReportingRewardPercentage` (e.g., 0) + +**Deployment Command**: + +```bash +forge create --rpc-url $L1RPC --private-key $PVK lib/avalanche-interchain-token-transfer/contracts/src/TokenRemote/NativeTokenRemote.sol:NativeTokenRemote --constructor-args "(${TELEPORTER_REGISTRY_L1}, ${myAddress}, ${C_CHAIN_BLOCKCHAIN_ID_HEX}, ${TOKEN_HOME}, 6)" "USDC", 10000000000000000000 0 + +export TOKEN_REMOTE=0xf06e68F0992cE0C350C6cE8bCa18aA6.... #This should be your tokenRemote address +``` + +### 4. **Minting Rights and Registration** + +1. **Add Remote Token Contract**: + + ```bash + cast send --rpc-url $L1RPC --private-key $PVK 0x0200000000000000000000000000000000000001 "setEnabled(address)" $TOKEN_REMOTE + ``` + +2. **Register Remote Token**: + + ```bash + cast send --rpc-url $L1RPC --private-key $PVK $TOKEN_REMOTE "registerWithHome((address,uint256))" "(0x0000000000000000000000000000000000000000,0)" + ``` + +3. **Collateralize the Home Transferer**: + + ```bash + cast send --rpc-url $CRPC --private-key $PVK $USDC_TOKEN_ADDRESS "approve(address, uint256)" $TOKEN_HOME 1000000 #your initial reserve imbalance + cast send --rpc-url $CRPC --private-key $PVK $TOKEN_HOME "addCollateral(bytes32, address, uint256)" $L1_BLOCKCHAIN_ID_HEX $TOKEN_REMOTE 10000000 + #Initial value minted when creating L1 + ``` + + +### 5. **Testing Interchain Token Transfers** + +To test sending interchain tokens: + +1. **Approve Additional Tokens**: + + ```bash + cast send --rpc-url $CRPC --private-key $PVK $USDC_TOKEN_ADDRESS "approve(address, uint256)" $TOKEN_HOME 1000000 + ``` + +2. **From C-chain to L1**: + + ```bash + cast send --rpc-url $CRPC --private-key $PVK $TOKEN_HOME "send((bytes32, address, address, address, uint256, uint256, uint256, address), uint256)" "(${L1_BLOCKCHAIN_ID_HEX}, ${TOKEN_REMOTE}, ${myAddress}, ${USDC_TOKEN_ADDRESS}, 0, 0, 250000, 0x0000000000000000000000000000000000000000)" 1000000 + ``` + +3. **From L1 to C-chain**: + + ```bash + cast send --rpc-url $L1RPC --private-key $PVK $TOKEN_REMOTE "send((bytes32,address,address,address,uint256,uint256,uint256,address))" "(${C_CHAIN_BLOCKCHAIN_ID_HEX},${TOKEN_HOME},${myAddress},${TOKEN_HOME},0,0,250000,0x0000000000000000000000000000000000000000)" --value 1ether + ``` + + +Now that we have a working bridge, let's talk about its important functions + +Send tokens +This function is the most basic function of the bridge and it is possible to send tokens to any network, regardless of whether it is token home or token remote. + +Send token and call functions + +This feature allows us to call a function after bridging the tokens, which can send the orgin sender address parameter so that secure dApps can be built that work with the bridge. + +Now we can start building 🧱 + +# Deploying Contracts for Multichain E-Commerce + +Similar to bridge contracts, this setup requires both a home contract and remote contracts. + +## Receiving Cross-Chain Payments + +The `ECommerceHome` contract is designed to interact with remote contracts on other blockchain networks. When a cross-chain payment is sent to the `ECommerceHome` contract, the process unfolds as follows: + +1. **Payment Initiation on Remote Network:** A user on a remote network initiates a transaction, such as purchasing a product. This interaction triggers the remote contract to communicate with the `ECommerceHome` contract on the home chain. +2. **Cross-Chain Message Transfer:** The remote contract sends a cross-chain message (via Avalanche Warp Messaging (AWM)). This message includes the payment details, such as the product ID, buyer, payment amount, and other necessary metadata. +3. **Payment Reception and Processing:** When the `ECommerceHome` contract receives the cross-chain message, it verifies the information, such as the origin network, transaction validity, and sender’s identity. Upon successful verification, the `ECommerceHome` contract processes the payment, updates the product status (e.g., marking it as sold), and registers the buyer in its system. +4. **Completion and Confirmation:** The payment is finalized on the home chain, and the buyer, seller, or other relevant parties are notified of the successful transaction. The product ownership can be updated, and any relevant details are stored in the contract. + +### Sending Cross-Chain Payments + +The `ECommerceHome` contract can also initiate cross-chain payments, typically when a user from the home network is purchasing a product listed on a different chain. Here’s how it works: + +1. **Purchase on Home Chain:** A buyer interacts with the `ECommerceHome` contract on the home network to purchase a product that might reside on a remote network. The contract handles the local payment processing (such as confirming the buyer has the required funds). +2. **Cross-Chain Payment Request:** Once the transaction is processed on the home chain, the `ECommerceHome` contract generates a cross-chain message. This message contains all relevant payment details, including product information, payment amount, and recipient data. +3. **Sending the Payment Across Chains:** The cross-chain message is relayed through a bridge to the corresponding `ECommerceRemote` contract on the target network. The bridge ensures secure transmission of the payment data between chains. + +## **Multichain E-Commerce Contracts Deployments** + +### Native Home E-Commerce Contract Deployment + +To deploy the Native Home E-Commerce contract, use the following command: + +```bash +forge create --rpc-url $L1RPC --private-key $PVK src/MultichainEcommerce/NativeMultichainEcommerceHome.sol:NativeMultichainEcommerceHome --constructor-args $TELEPORTER_REGISTRY_L1 $myAddress 1 $TOKEN_REMOTE $L1_BLOCKCHAIN_ID_HEX $C_CHAIN_BLOCKCHAIN_ID_HEX +export E_COMMERCE_HOME_ADDRESS=0xB6860E75Cae7CBc91Ca... #Your deployment address +``` + +Once deployed, the contract address will be saved to the `E_COMMERCE_HOME_ADDRESS` environment variable for future use. + +### ERC20 Remote E-Commerce Contract Deployment + +To deploy the ERC20 Remote E-Commerce contract, use the following command: + +```bash +forge create --rpc-url $CRPC --private-key $PVK src/MultichainEcommerce/ERC20MultichainEcommerceRemote.sol:ERC20MultichainEcommerceRemote --constructor-args $TELEPORTER_REGISTRY_C_CHAIN $myAddress 1 $TOKEN_HOME $TOKEN_REMOTE $L1_BLOCKCHAIN_ID_HEX $E_COMMERCE_HOME_ADDRESS $USDC_TOKEN_ADDRESS $C_CHAIN_BLOCKCHAIN_ID_HEX +export E_COMMERCE_REMOTE_ADDRESS=0x0A654ad1Bb7C5F1Ed0413E6c60817Ea4EfC24281 +``` + +Once deployed, the contract address will be saved to the `E_COMMERCE_REMOTE_ADDRESS` environment variable for future reference. + +### E-Commerce Set Active Remote + +Remote addresses needs to be secure so only allowed remote contracts can interact with it + +```bash +cast send --rpc-url $L1RPC --private-key $PVK $E_COMMERCE_HOME_ADDRESS "_setActiveRemote(address,bytes32,address)" $E_COMMERCE_REMOTE_ADDRESS $C_CHAIN_BLOCKCHAIN_ID_HEX $TOKEN_HOME +``` + +After this step ECommerceHome contract can recieve and send cross-chain payments + +### E-Commerce Cross-Chain Add Product + +When adding products, the price should be set based on the decimal precision defined by the `ECommerceHome` contract. This ensures consistent pricing across the platform, especially when dealing with different token standards that might have varying decimal places. + +```bash +cast send --rpc-url $CRPC --private-key $PVK $E_COMMERCE_REMOTE_ADDRESS "crossChainAddProduct(uint256,string)" 2000000000000000000 "TEST Product" +cast call --rpc-url $L1RPC $E_COMMERCE_HOME_ADDRESS "getProduct(uint256)((address,uint256,uint8,address,string,bytes32,uint256))" 0 #You should see the product you have added +``` + +### E-Commerce Cross-Chain Buy Product + +```bash +cast send --rpc-url $CRPC --private-key $PVK $USDC_TOKEN_ADDRESS "approve(address, uint256)" $E_COMMERCE_REMOTE_ADDRESS 2000000 +cast send --rpc-url $CRPC --private-key $PVK $E_COMMERCE_REMOTE_ADDRESS "crossChainBuyProduct(uint256,uint256)" 0 2000000 +cast call --rpc-url $L1RPC $E_COMMERCE_HOME_ADDRESS "getProductStatus(uint256)(uint8)" 0 #You should see the status is 1 if not wait for relayer to finish executing message +``` + +### Cross-Chain Dex ERC20 Contract Deployment + +To deploy the Cross-Chain Dex ERC20 contract, which handles swap operations across chains, you can use the following command: + +```bash +export TJ_FACTORY_ADDRES=0xF5c7d9733e5f53abCC1695820c4818C59B457C2C +export WRAPPED_NATIVE_FUJI=0xd00ae08403B9bbb9124bB305C09058E32C39A48c +forge create --rpc-url $CRPC --private-key $PVK src/10-cross-chain-token-swaps/DexERC20Wrapper.sol:DexERC20Wrapper --constructor-args $WRAPPED_NATIVE_FUJI $TJ_FACTORY_ADDRES +``` + +This command deploys a operational Dex Erc20 contract to Fuji C-Chain \ No newline at end of file diff --git a/src/MultichainEcommerce/ERC20MultichainEcommerceHome.sol b/src/MultichainEcommerce/ERC20MultichainEcommerceHome.sol new file mode 100644 index 00000000..f451c0be --- /dev/null +++ b/src/MultichainEcommerce/ERC20MultichainEcommerceHome.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {SendAndCallInput} from "@avalanche-interchain-token-transfer/interfaces/ITokenBridge.sol"; +import {IERC20TokenBridge} from "@avalanche-interchain-token-transfer/interfaces/IERC20TokenBridge.sol"; +import {IERC20CommerceHome} from "./interfaces/IERC20CommerceHome.sol"; +import { + IProduct, + CommerceMessageType, + ICommerceMessage, + ICrossChainPayment, + ITokenSentMessage, + ICrossChainPaymentResult, + IProductInput, + ProductStatus +} from "./interfaces/IECommerce.sol"; +import {TeleporterOwnerUpgradeable} from "@teleporter/upgrades/TeleporterOwnerUpgradeable.sol"; +import {IERC20SendAndCallReceiver} from "@avalanche-interchain-token-transfer/interfaces/IERC20SendAndCallReceiver.sol"; +import {SafeERC20} from "@openzeppelin/contracts@4.8.1/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts@4.8.1/token/ERC20/ERC20.sol"; + +contract ERC20MultichainEcommerceHome is IERC20CommerceHome, TeleporterOwnerUpgradeable, IERC20SendAndCallReceiver { + using SafeERC20 for IERC20; + + IERC20TokenBridge ERC20TokenTransferrer; + IERC20 ERC20TOKEN; + mapping(uint256 => IProduct) public products; + mapping(address => uint256[]) public sellerToProducts; + mapping(bytes32 => address) public activeRemotes; + mapping(bytes32 => address) public activeTokenTransferrer; + bytes32 public remoteBlockchainID; + bytes32 public homeBlockchainId; + uint256 public constant MIN_AMOUNT = 10 ** 6; + uint256 public lastProductId = 0; + bytes32 homeTokenTransferrerBlockchainID; + + constructor( + address teleporterRegistryAddress, + address initialOwner, + address ERC20TokenTransferrer_, + bytes32 homeBlockchainId_, + bytes32 remoteBlockchainID_, + address erc20Address_, + bytes32 homeTokenTransferrerBlockchainID_ + ) TeleporterOwnerUpgradeable(teleporterRegistryAddress, initialOwner) { + ERC20TokenTransferrer = IERC20TokenBridge(ERC20TokenTransferrer_); + + homeBlockchainId = homeBlockchainId_; + activeRemotes[homeBlockchainId_] = ERC20TokenTransferrer_; + remoteBlockchainID = remoteBlockchainID_; + ERC20TOKEN = IERC20(erc20Address_); + homeTokenTransferrerBlockchainID = homeTokenTransferrerBlockchainID_; + } + + //this function only callable from e-commerce remote. + //make sure the remote contract is secure. otherwise if payments failed then fund trasfer wrong address. + //ICTT bridge and _buyProduct already protected against reentrancy attack, so no need to check it again. + // payload type is struct ITokenSentMessage (address buyer,uint256[] productIds) decode and call standard buying procces + + function receiveTokens( + bytes32 sourceBlockchainID, + address originTokenTransferrerAddress, + address originSenderAddress, + address token, + uint256 amount, + bytes calldata payload + ) external { + require(msg.sender == address(ERC20TokenTransferrer), "not authorize"); + require(originTokenTransferrerAddress == activeTokenTransferrer[sourceBlockchainID], "not authorize"); + require(originSenderAddress == activeRemotes[sourceBlockchainID]); + ITokenSentMessage memory message = abi.decode(payload, (ITokenSentMessage)); + require(token == address(ERC20TOKEN), "invalid token"); + ERC20TOKEN.safeTransferFrom(msg.sender, address(this), amount); + _buyProduct(message.productId, message.buyer, amount); + } + + //this function allows the owner to authorize active remote contracts. + //remote address should be the address on the chain given the blockhain id. + function _setActiveRemote(address remoteaddr, bytes32 chainID, address remoteTokenTransferrerAddress) + external + onlyOwner + { + activeRemotes[chainID] = remoteaddr; + activeTokenTransferrer[chainID] = remoteTokenTransferrerAddress; + } + //used for receptions in the same chain Since the called function is specified as nonReentrant, it does not need to be specified as nonReentrant again + + function buyProduct(uint256 _productId, uint256 amount) public { + ERC20TOKEN.safeTransferFrom(msg.sender, address(this), amount); + address _buyer = msg.sender; + require(amount >= MIN_AMOUNT, "payment is too low"); + _buyProduct(_productId, _buyer, amount); + } + //This function allows the user to add one or more products. + + function addProduct(IProductInput memory _product) public { + IProductInput memory input = _product; + IProduct memory created = IProduct({ + seller: msg.sender, + price: input.price, + status: ProductStatus.ACTIVE, + buyer: address(0), + title: input.title, + sellerBlockchainId: homeBlockchainId, + pendingDeadline: 0 + }); + _addProduct(created, msg.sender); + } + + function activeRemoteAddress(bytes32 remote) public view returns (address) { + address remoteECommerce = activeRemotes[remote]; + return remoteECommerce; + } + + function getProduct(uint256 id) public view returns (IProduct memory product) { + return (products[id]); + } + + function getProductStatus(uint256 productId) public view returns (ProductStatus) { + return (products[productId].status); + } + + function getSellerToProducts(address seller) public view returns (uint256[] memory) { + uint256[] memory userProducts = sellerToProducts[seller]; + return userProducts; + } + // for cross chain products handle + + function crosschainAddProduct(IProductInput memory _product, bytes32 blockchainId, address client) internal { + require(activeRemotes[blockchainId] != address(0), "chain is not registered"); + IProductInput memory input = _product; + IProduct memory created = IProduct({ + seller: client, + price: input.price, + status: ProductStatus.ACTIVE, + buyer: address(0), + title: input.title, + sellerBlockchainId: blockchainId, + pendingDeadline: 0 + }); + _addProduct(created, client); + } + + function _addProduct(IProduct memory _product, address _sender) internal { + uint256 addedProductId = lastProductId; + lastProductId++; + address sender = _sender; + require(sender != address(0), "invalid address"); + require(products[addedProductId].seller == address(0), "already claimed id"); + require(_product.price >= MIN_AMOUNT, "price is too low"); + products[addedProductId] = _product; + sellerToProducts[sender].push(addedProductId); + emit ProductAdded(addedProductId, _sender); + } + + function _buyProduct(uint256 _product, address _buyer, uint256 amount) internal nonReentrant { + IProduct memory selected = products[_product]; + require(_product <= lastProductId, "product not found"); + require(selected.price <= amount); + require(activeRemotes[selected.sellerBlockchainId] != address(0), "chain is not registered"); + require(selected.status == ProductStatus.ACTIVE, "product not active"); + products[_product].buyer = _buyer; + if (selected.sellerBlockchainId != homeBlockchainId) { + ICrossChainPayment memory payment = + ICrossChainPayment({receiverAddress: selected.seller, productId: _product, buyer: _buyer}); + sendCrossChainPayment(payment, _buyer, selected.price, selected.sellerBlockchainId); + products[_product].status = ProductStatus.PENDING; + products[_product].pendingDeadline = block.timestamp + 1 hours; + products[_product].buyer = _buyer; + emit ProductsBuy(_product, _buyer, selected.price, selected.seller, selected.sellerBlockchainId); + } else { + selected.status = ProductStatus.SOLD; + ERC20TOKEN.safeTransfer(selected.seller, selected.price); + emit ProductsBuy(_product, _buyer, selected.price, selected.seller, selected.sellerBlockchainId); + emit PaymentSuccessful(_product, _buyer, selected.sellerBlockchainId, selected.seller); + } + } + + function sendCrossChainPayment( + ICrossChainPayment memory payment, + address buyer, + uint256 value, + bytes32 sellerBlockchainId + ) internal { + bool isSingleHop = ( + (homeBlockchainId == homeTokenTransferrerBlockchainID) + || (sellerBlockchainId == homeTokenTransferrerBlockchainID) + ); + ERC20TokenTransferrer.sendAndCall( + SendAndCallInput({ + destinationBlockchainID: remoteBlockchainID, + destinationBridgeAddress: activeTokenTransferrer[sellerBlockchainId], + recipientContract: activeRemotes[sellerBlockchainId], + recipientPayload: abi.encode(payment), + requiredGasLimit: 500_000, + recipientGasLimit: 350_000, + multiHopFallback: isSingleHop ? address(0) : buyer, + fallbackRecipient: buyer, + primaryFeeTokenAddress: activeTokenTransferrer[sellerBlockchainId], + primaryFee: 0, + secondaryFee: 0 + }), + value + ); + } + + function _receiveTeleporterMessage(bytes32 sourceBlockchainID, address originSenderAddress, bytes memory message) + internal + override + { + require(activeRemotes[sourceBlockchainID] == originSenderAddress, "remote not registered"); + ICommerceMessage memory payload = abi.decode(message, (ICommerceMessage)); + if (payload.message_type == CommerceMessageType.ADD_PRODUCT) { + IProductInput memory productDetails = abi.decode(payload.payload, (IProductInput)); + crosschainAddProduct(productDetails, sourceBlockchainID, payload.client); + } else if (payload.message_type == CommerceMessageType.PAYMENT_RESULT) { + ICrossChainPaymentResult memory result = abi.decode(payload.payload, (ICrossChainPaymentResult)); + if (result.success) { + require(products[result.productId].status == ProductStatus.PENDING, "product is not buying proccess"); + products[result.productId].status = ProductStatus.SOLD; + emit PaymentSuccessful(result.productId, result.buyer, sourceBlockchainID, payload.client); + products[result.productId].buyer = result.buyer; + } else { + require(products[result.productId].status == ProductStatus.PENDING, "product is not buying proccess"); + products[result.productId].status = ProductStatus.ACTIVE; + products[result.productId].buyer = address(0); + emit PaymentFailed(result.productId, result.buyer); + } + } + } +} diff --git a/src/MultichainEcommerce/ERC20MultichainEcommerceRemote.sol b/src/MultichainEcommerce/ERC20MultichainEcommerceRemote.sol new file mode 100644 index 00000000..294cb1f8 --- /dev/null +++ b/src/MultichainEcommerce/ERC20MultichainEcommerceRemote.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {TeleporterOwnerUpgradeable} from "@teleporter/upgrades/TeleporterOwnerUpgradeable.sol"; +import { + CommerceMessageType, + ICommerceMessage, + ICrossChainPayment, + ITokenSentMessage, + ICrossChainPaymentResult, + IProductInput +} from "./interfaces/IECommerce.sol"; +import {IERC20CommerceRemote} from "./interfaces/IERC20CommerceRemote.sol"; +import {IERC20SendAndCallReceiver} from "@avalanche-interchain-token-transfer/interfaces/IERC20SendAndCallReceiver.sol"; +import {IERC20TokenBridge} from "@avalanche-interchain-token-transfer/interfaces/IERC20TokenBridge.sol"; +import {IERC20} from "@openzeppelin/contracts@4.8.1/token/ERC20/ERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts@4.8.1/token/ERC20/utils/SafeERC20.sol"; +import {TeleporterMessageInput, TeleporterFeeInfo} from "@teleporter/ITeleporterMessenger.sol"; +import {SendAndCallInput} from "@avalanche-interchain-token-transfer/interfaces/ITokenBridge.sol"; + +contract ERC20MultichainEcommerceRemote is + IERC20CommerceRemote, + TeleporterOwnerUpgradeable, + IERC20SendAndCallReceiver +{ + using SafeERC20 for IERC20; + + IERC20 public ERC20Token; + IERC20TokenBridge public ERC20TokenTransferrer; + address public eCommerceHomeTokenTransferrer; + bytes32 public eCommerceHomeblockchainId; + address public homeAddress; + bytes32 public homeTokenTransferrerBlockchainID; + bytes32 public blockchainId; + + constructor( + address teleporterRegistryAddress, + address initialOwner, + address ERC20TokenTransferrer_, + address eCommerceHomeTokenTransferrer_, + bytes32 eCommerceHomeblockchainId_, + address homeAddress_, + address erc20Address_, + bytes32 homeTokenTransferrerBlockchainID_, + bytes32 blockchainId_ + ) TeleporterOwnerUpgradeable(teleporterRegistryAddress, initialOwner) { + ERC20TokenTransferrer = IERC20TokenBridge(ERC20TokenTransferrer_); + eCommerceHomeTokenTransferrer = eCommerceHomeTokenTransferrer_; + eCommerceHomeblockchainId = eCommerceHomeblockchainId_; + homeAddress = homeAddress_; + homeTokenTransferrerBlockchainID = homeTokenTransferrerBlockchainID_; + ERC20Token = IERC20(erc20Address_); + blockchainId = blockchainId_; + } + + function receiveTokens( + bytes32 sourceBlockchainID, + address originTokenTransferrerAddress, + address originSenderAddress, + address token, + uint256 amount, + bytes calldata payload + ) external { + require(sourceBlockchainID == eCommerceHomeblockchainId, "only home"); + require(originTokenTransferrerAddress == eCommerceHomeTokenTransferrer, "only home"); + require(originSenderAddress == address(homeAddress), "only home"); + IERC20 Token = IERC20(token); + + Token.transferFrom(msg.sender, address(this), amount); + ICrossChainPayment memory payment = abi.decode(payload, (ICrossChainPayment)); + + if (payment.receiverAddress == address(0)) { + emit crossChainPaymentFailed(payment.receiverAddress, payment.buyer, payment.productId); + _sendToFallbackReceiver(payment.buyer, amount); + ICrossChainPaymentResult memory paymentsReceipt = + ICrossChainPaymentResult({productId: payment.productId, success: false, buyer: payment.buyer}); + + sendResultToHome(paymentsReceipt, payment.buyer); + } + (bool success,) = address(Token).call(abi.encodeCall(Token.transfer, (payment.receiverAddress, amount))); + if (success) { + emit crossChainPaymentReceived(payment.receiverAddress, payment.buyer, payment.productId); + + ICrossChainPaymentResult memory paymentsReceipt = + ICrossChainPaymentResult({productId: payment.productId, success: true, buyer: payment.buyer}); + sendResultToHome(paymentsReceipt, payment.buyer); + } else { + emit crossChainPaymentFailed(payment.receiverAddress, payment.buyer, payment.productId); + + ICrossChainPaymentResult memory paymentsReceipt = + ICrossChainPaymentResult({productId: payment.productId, success: false, buyer: payment.buyer}); + + _sendToFallbackReceiver(payment.buyer, amount); + sendResultToHome(paymentsReceipt, payment.buyer); + } + } + + function crossChainBuyProduct(uint256 productId, uint256 value) public { + ERC20Token.safeTransferFrom(msg.sender, address(this), value); + ERC20Token.safeIncreaseAllowance(address(ERC20TokenTransferrer), value); + bool isSingleHop = ( + (eCommerceHomeblockchainId == homeTokenTransferrerBlockchainID) + || (blockchainId == homeTokenTransferrerBlockchainID) + ); + ERC20TokenTransferrer.sendAndCall( + SendAndCallInput({ + destinationBlockchainID: eCommerceHomeblockchainId, + destinationBridgeAddress: eCommerceHomeTokenTransferrer, + recipientContract: address(homeAddress), + recipientPayload: abi.encode(ITokenSentMessage({buyer: msg.sender, productId: productId})), + requiredGasLimit: 900_000, + recipientGasLimit: 700_000, + multiHopFallback: isSingleHop ? address(0) : msg.sender, + fallbackRecipient: msg.sender, + primaryFeeTokenAddress: address(ERC20Token), + primaryFee: 0, + secondaryFee: 0 + }), + value + ); + ERC20Token.safeApprove(address(ERC20TokenTransferrer), 0); + emit crossChainProductBuy(msg.sender, value); + } + + function crossChainAddProduct(uint256 price, string memory title) public { + _sendTeleporterMessage( + TeleporterMessageInput({ + destinationBlockchainID: eCommerceHomeblockchainId, + destinationAddress: address(homeAddress), + feeInfo: TeleporterFeeInfo({feeTokenAddress: address(ERC20Token), amount: 0}), + requiredGasLimit: 350_000, + allowedRelayerAddresses: new address[](0), + message: abi.encode( + ICommerceMessage({ + message_type: CommerceMessageType.ADD_PRODUCT, + client: msg.sender, + payload: abi.encode(IProductInput({price: price, title: title})) + }) + ) + }) + ); + emit crossChainProductAdded(msg.sender); + } + + function sendResultToHome(ICrossChainPaymentResult memory receipt, address client) internal { + bytes memory message = abi.encode(receipt); + bytes memory data = abi.encode( + ICommerceMessage({message_type: CommerceMessageType.PAYMENT_RESULT, client: client, payload: message}) + ); + _sendTeleporterMessage( + TeleporterMessageInput({ + destinationBlockchainID: eCommerceHomeblockchainId, + destinationAddress: address(homeAddress), + feeInfo: TeleporterFeeInfo({feeTokenAddress: address(ERC20Token), amount: 0}), + requiredGasLimit: 150_000, + allowedRelayerAddresses: new address[](0), + message: data + }) + ); + } + + function _receiveTeleporterMessage(bytes32 sourceBlockchainID, address originSenderAddress, bytes memory message) + internal + override + {} + + function _sendToFallbackReceiver(address fallbackAddress, uint256 amount) internal { + (bool fallbackSuccess,) = + address(ERC20Token).call(abi.encodeCall(ERC20Token.transfer, (fallbackAddress, amount))); + if (!fallbackSuccess) { + address(ERC20Token).call(abi.encodeCall(ERC20Token.approve, (fallbackAddress, amount))); + } + } +} diff --git a/src/MultichainEcommerce/NativeMultichainEcommerceHome.sol b/src/MultichainEcommerce/NativeMultichainEcommerceHome.sol new file mode 100644 index 00000000..5fa16d7d --- /dev/null +++ b/src/MultichainEcommerce/NativeMultichainEcommerceHome.sol @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {SendAndCallInput} from "@avalanche-interchain-token-transfer/interfaces/ITokenBridge.sol"; +import {INativeTokenBridge} from "@avalanche-interchain-token-transfer/interfaces/INativeTokenBridge.sol"; +import {INativeCommerceHome} from "./interfaces/INativeCommerceHome.sol"; +import { + IProduct, + CommerceMessageType, + ICommerceMessage, + ICrossChainPayment, + ITokenSentMessage, + ICrossChainPaymentResult, + IProductInput, + ProductStatus +} from "./interfaces/IECommerce.sol"; +import {TeleporterOwnerUpgradeable} from "@teleporter/upgrades/TeleporterOwnerUpgradeable.sol"; +import {INativeSendAndCallReceiver} from + "@avalanche-interchain-token-transfer/interfaces/INativeSendAndCallReceiver.sol"; + +contract NativeMultichainEcommerceHome is + INativeCommerceHome, + TeleporterOwnerUpgradeable, + INativeSendAndCallReceiver +{ + INativeTokenBridge NativeTokenTransferrer; + bytes32 homeTokenTransferrerBlockchainID; + mapping(uint256 => IProduct) public products; + mapping(address => uint256[]) public sellerToProducts; + mapping(bytes32 => address) public activeRemotes; + mapping(bytes32 => address) public activeTokenTransferrer; + bytes32 public homeBlockchainId; + uint256 public constant MIN_AMOUNT = 10 ** 12; + uint256 public lastProductId = 0; + + constructor( + address teleporterRegistryAddress, + address initialOwner, + address nativeTokenTransferrer_, + bytes32 homeBlockchainId_, + bytes32 homeTokenTransferrerBlockchainID_ + ) TeleporterOwnerUpgradeable(teleporterRegistryAddress, initialOwner) { + NativeTokenTransferrer = INativeTokenBridge(nativeTokenTransferrer_); + + homeBlockchainId = homeBlockchainId_; + activeRemotes[homeBlockchainId_] = nativeTokenTransferrer_; + activeTokenTransferrer[homeBlockchainId_] = address(this); + homeTokenTransferrerBlockchainID = homeTokenTransferrerBlockchainID_; + } + + //this function only callable from e-commerce remote. + //make sure the remote contract is secure. otherwise if payments failed then fund trasfer wrong address. + //ICTT bridge and _buyProduct already protected against reentrancy attack, so no need to check it again. + // payload type is struct ITokenSentMessage (address buyer,uint256[] productIds) decode and call standard buying procces + + function receiveTokens( + bytes32 sourceBlockchainID, + address originTokenTransferrerAddress, + address originSenderAddress, + bytes calldata payload + ) external payable { + require(msg.sender == address(NativeTokenTransferrer), "not authorize"); + require(originTokenTransferrerAddress == activeTokenTransferrer[sourceBlockchainID], "not authorize"); + require(originSenderAddress == activeRemotes[sourceBlockchainID]); + ITokenSentMessage memory message = abi.decode(payload, (ITokenSentMessage)); + _buyProduct(message.productId, message.buyer); + } + + //this function allows the owner to authorize active remote contracts. + //remote address should be the address on the chain given the blockhain id. + function _setActiveRemote(address remoteaddr, bytes32 chainID, address remoteTokenTransferrerAddress) + external + onlyOwner + { + activeRemotes[chainID] = remoteaddr; + activeTokenTransferrer[chainID] = remoteTokenTransferrerAddress; + } + //used for receptions in the same chain Since the called function is specified as nonReentrant, it does not need to be specified as nonReentrant again + + function buyProduct(uint256 _productId) public payable { + address _buyer = msg.sender; + require(msg.value >= MIN_AMOUNT, "payment is too low"); + _buyProduct(_productId, _buyer); + } + //This function allows the user to add one or more products. + + function addProduct(IProductInput memory _product) public { + IProductInput memory input = _product; + IProduct memory created = IProduct({ + seller: msg.sender, + price: input.price, + status: ProductStatus.ACTIVE, + buyer: address(0), + title: input.title, + sellerBlockchainId: homeBlockchainId, + pendingDeadline: 0 + }); + _addProduct(created, msg.sender); + } + + function activeRemoteAddress(bytes32 remote) public view returns (address) { + address remoteECommerce = activeRemotes[remote]; + return remoteECommerce; + } + + function getProduct(uint256 id) public view returns (IProduct memory product) { + return (products[id]); + } + + function getProductStatus(uint256 productId) public view returns (ProductStatus) { + return (products[productId].status); + } + + function getSellerToProducts(address seller) public view returns (uint256[] memory) { + uint256[] memory userProducts = sellerToProducts[seller]; + return userProducts; + } + // for cross chain products handle + + function crosschainAddProduct(IProductInput memory _product, bytes32 blockchainId, address client) internal { + require(activeRemotes[blockchainId] != address(0), "chain is not registered"); + IProductInput memory input = _product; + IProduct memory created = IProduct({ + seller: client, + price: input.price, + status: ProductStatus.ACTIVE, + buyer: address(0), + title: input.title, + sellerBlockchainId: blockchainId, + pendingDeadline: 0 + }); + _addProduct(created, client); + } + + function _addProduct(IProduct memory _product, address _sender) internal { + uint256 addedProductId = lastProductId; + lastProductId++; + address sender = _sender; + require(sender != address(0), "invalid address"); + require(products[addedProductId].seller == address(0), "already claimed id"); + require(_product.price >= MIN_AMOUNT, "price is too low"); + products[addedProductId] = _product; + sellerToProducts[sender].push(addedProductId); + emit ProductAdded(addedProductId, _sender); + } + + function _buyProduct(uint256 _product, address _buyer) internal nonReentrant { + IProduct memory selected = products[_product]; + require(_product <= lastProductId, "product not found"); + require(selected.price <= msg.value); + require(activeRemotes[selected.sellerBlockchainId] != address(0), "chain is not registered"); + require(selected.status == ProductStatus.ACTIVE, "product not active"); + selected.buyer = _buyer; + if (selected.sellerBlockchainId != homeBlockchainId) { + ICrossChainPayment memory payment = + ICrossChainPayment({receiverAddress: selected.seller, productId: _product, buyer: _buyer}); + sendCrossChainPayment(payment, _buyer, selected.price, selected.sellerBlockchainId); + products[_product].status = ProductStatus.PENDING; + products[_product].pendingDeadline = block.timestamp + 1 hours; + emit ProductsBuy(_product, _buyer, selected.price, selected.seller, selected.sellerBlockchainId); + } else { + (bool sent,) = selected.seller.call{value: selected.price}(""); + require(sent, "transfer failed"); + products[_product].status = ProductStatus.SOLD; + products[_product].buyer = _buyer; + emit ProductsBuy(_product, _buyer, selected.price, selected.seller, selected.sellerBlockchainId); + emit PaymentSuccessful(_product, _buyer, selected.sellerBlockchainId, selected.seller); + } + } + + function sendCrossChainPayment( + ICrossChainPayment memory payment, + address buyer, + uint256 value, + bytes32 sellerBlockchainId + ) internal { + require(activeTokenTransferrer[sellerBlockchainId] != address(0), "remote not registered"); + require(activeRemotes[sellerBlockchainId] != address(0), "remote not registered"); + bool isSingleHop = ( + (homeBlockchainId == homeTokenTransferrerBlockchainID) + || (sellerBlockchainId == homeTokenTransferrerBlockchainID) + ); + NativeTokenTransferrer.sendAndCall{value: value}( + SendAndCallInput({ + destinationBlockchainID: sellerBlockchainId, + destinationBridgeAddress: activeTokenTransferrer[sellerBlockchainId], + recipientContract: activeRemotes[sellerBlockchainId], + recipientPayload: abi.encode(payment), + requiredGasLimit: 500_000, + recipientGasLimit: 350_000, + multiHopFallback: isSingleHop ? address(0) : buyer, + fallbackRecipient: buyer, + primaryFeeTokenAddress: activeTokenTransferrer[sellerBlockchainId], + primaryFee: 0, + secondaryFee: 0 + }) + ); + } + + function _receiveTeleporterMessage(bytes32 sourceBlockchainID, address originSenderAddress, bytes memory message) + internal + override + { + require(activeRemotes[sourceBlockchainID] != address(0), "remote not registered"); + ICommerceMessage memory payload = abi.decode(message, (ICommerceMessage)); + if (payload.message_type == CommerceMessageType.ADD_PRODUCT) { + require(originSenderAddress == activeRemotes[sourceBlockchainID]); + IProductInput memory productDetails = abi.decode(payload.payload, (IProductInput)); + crosschainAddProduct(productDetails, sourceBlockchainID, payload.client); + } else if (payload.message_type == CommerceMessageType.PAYMENT_RESULT) { + ICrossChainPaymentResult memory result = abi.decode(payload.payload, (ICrossChainPaymentResult)); + if (result.success) { + require(products[result.productId].status == ProductStatus.PENDING, "product is not buying proccess"); + products[result.productId].status = ProductStatus.SOLD; + products[result.productId].buyer = result.buyer; + emit PaymentSuccessful(result.productId, result.buyer, sourceBlockchainID, payload.client); + } else { + require(products[result.productId].status == ProductStatus.PENDING, "product is not buying proccess"); + products[result.productId].status = ProductStatus.ACTIVE; + emit PaymentFailed(result.productId, result.buyer); + } + } + } +} diff --git a/src/MultichainEcommerce/NativeMultichainEcommerceRemote.sol b/src/MultichainEcommerce/NativeMultichainEcommerceRemote.sol new file mode 100644 index 00000000..215edfdb --- /dev/null +++ b/src/MultichainEcommerce/NativeMultichainEcommerceRemote.sol @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {TeleporterOwnerUpgradeable} from "@teleporter/upgrades/TeleporterOwnerUpgradeable.sol"; +import { + CommerceMessageType, + ICommerceMessage, + ICrossChainPayment, + ITokenSentMessage, + ICrossChainPaymentResult, + IProductInput +} from "./interfaces/IECommerce.sol"; +import {INativeCommerceRemote} from "./interfaces/INativeCommerceRemote.sol"; +import {INativeTokenBridge} from "@avalanche-interchain-token-transfer/interfaces/INativeTokenBridge.sol"; +import {TeleporterMessageInput, TeleporterFeeInfo} from "@teleporter/ITeleporterMessenger.sol"; +import {SendAndCallInput, SendTokensInput} from "@avalanche-interchain-token-transfer/interfaces/ITokenBridge.sol"; +import {INativeSendAndCallReceiver} from + "@avalanche-interchain-token-transfer/interfaces/INativeSendAndCallReceiver.sol"; + +contract NativeMultichainEcommerceRemote is + INativeCommerceRemote, + TeleporterOwnerUpgradeable, + INativeSendAndCallReceiver +{ + INativeTokenBridge public RemoteTokenTransferrer; + address public eCommerceHomeTokenTransferrer; + bytes32 public blockchainId; + bytes32 public eCommerceHomeblockchainId; + address CommerceHome; + bytes32 homeTokenTransferrerBlockchainID; + + constructor( + address teleporterRegistryAddress, + address initialOwner, + address RemoteTokenTransferrer_, + address eCommerceHomeTokenTransferrer_, + bytes32 blockchainId_, + bytes32 eCommerceHomeblockchainId_, + address commerceHome_, + bytes32 homeTokenTransferrerBlockchainID_ + ) TeleporterOwnerUpgradeable(teleporterRegistryAddress, initialOwner) { + RemoteTokenTransferrer = INativeTokenBridge(RemoteTokenTransferrer_); + eCommerceHomeTokenTransferrer = eCommerceHomeTokenTransferrer_; + blockchainId = blockchainId_; + eCommerceHomeblockchainId = eCommerceHomeblockchainId_; + CommerceHome = commerceHome_; + homeTokenTransferrerBlockchainID = homeTokenTransferrerBlockchainID_; + } + + function receiveTokens( + bytes32 sourceBlockchainID, + address originTokenTransferrerAddress, + address originSenderAddress, + bytes calldata payload + ) external payable { + require(sourceBlockchainID == eCommerceHomeblockchainId, "only home"); + require(originTokenTransferrerAddress == eCommerceHomeTokenTransferrer, "only home"); + require(originSenderAddress == address(CommerceHome), "only home"); + ICrossChainPayment memory payment = abi.decode(payload, (ICrossChainPayment)); + if (payment.receiverAddress == address(0)) { + ICrossChainPaymentResult memory paymentReceipt = + ICrossChainPaymentResult({productId: payment.productId, success: false, buyer: payment.buyer}); + emit crossChainPaymentFailed(payment.receiverAddress, payment.buyer, payment.productId); + _sendToFallbackReceiver(payment.buyer, msg.value, originTokenTransferrerAddress, sourceBlockchainID); + sendResultToHome(paymentReceipt, payment.buyer); + } + (bool success,) = payment.receiverAddress.call{value: msg.value}(""); + if (success) { + emit crossChainPaymentReceived(payment.receiverAddress, payment.buyer, payment.productId); + + ICrossChainPaymentResult memory paymentReceipt = + ICrossChainPaymentResult({productId: payment.productId, success: true, buyer: payment.buyer}); + sendResultToHome(paymentReceipt, payment.buyer); + } else { + emit crossChainPaymentFailed(payment.receiverAddress, payment.buyer, payment.productId); + + ICrossChainPaymentResult memory paymentsReceipt = + ICrossChainPaymentResult({productId: payment.productId, success: false, buyer: payment.buyer}); + + _sendToFallbackReceiver(payment.buyer, msg.value, originTokenTransferrerAddress, sourceBlockchainID); + sendResultToHome(paymentsReceipt, payment.buyer); + } + } + + function crossChainBuyProduct(uint256 productId) public payable { + bool isSingleHop = ( + (blockchainId == homeTokenTransferrerBlockchainID) + || (eCommerceHomeblockchainId == homeTokenTransferrerBlockchainID) + ); + RemoteTokenTransferrer.sendAndCall{value: msg.value}( + SendAndCallInput({ + destinationBlockchainID: eCommerceHomeblockchainId, + destinationBridgeAddress: eCommerceHomeTokenTransferrer, + recipientContract: address(CommerceHome), + recipientPayload: abi.encode(ITokenSentMessage({buyer: msg.sender, productId: productId})), + requiredGasLimit: 900_000, + recipientGasLimit: 700_000, + multiHopFallback: isSingleHop ? address(0) : msg.sender, + fallbackRecipient: msg.sender, + primaryFeeTokenAddress: eCommerceHomeTokenTransferrer, + primaryFee: 0, + secondaryFee: 0 + }) + ); + } + + function crossChainAddProduct(uint256 price, string memory title) public { + _sendTeleporterMessage( + TeleporterMessageInput({ + destinationBlockchainID: eCommerceHomeblockchainId, + destinationAddress: address(CommerceHome), + feeInfo: TeleporterFeeInfo({feeTokenAddress: eCommerceHomeTokenTransferrer, amount: 0}), + requiredGasLimit: 350_000, + allowedRelayerAddresses: new address[](0), + message: abi.encode( + ICommerceMessage({ + message_type: CommerceMessageType.ADD_PRODUCT, + client: msg.sender, + payload: abi.encode(IProductInput({price: price, title: title})) + }) + ) + }) + ); + emit crossChainProductAdded(msg.sender); + } + + function sendResultToHome(ICrossChainPaymentResult memory receipt, address client) internal { + bytes memory message = abi.encode(receipt); + bytes memory data = abi.encode( + ICommerceMessage({message_type: CommerceMessageType.PAYMENT_RESULT, client: client, payload: message}) + ); + _sendTeleporterMessage( + TeleporterMessageInput({ + destinationBlockchainID: eCommerceHomeblockchainId, + destinationAddress: address(CommerceHome), + feeInfo: TeleporterFeeInfo({feeTokenAddress: eCommerceHomeTokenTransferrer, amount: 0}), + requiredGasLimit: 150_000, + allowedRelayerAddresses: new address[](0), + message: data + }) + ); + } + + function _receiveTeleporterMessage(bytes32 sourceBlockchainID, address originSenderAddress, bytes memory message) + internal + override + {} + + function _sendToFallbackReceiver( + address fallbackAddress, + uint256 amount, + address originTransferrer, + bytes32 destinationBlockchainId + ) internal { + (bool fallbackSuccess,) = address(fallbackAddress).call{value: amount}(""); + if (!fallbackSuccess) { + RemoteTokenTransferrer.send{value: msg.value}( + SendTokensInput({ + destinationBlockchainID: destinationBlockchainId, + destinationBridgeAddress: originTransferrer, + recipient: fallbackAddress, + primaryFeeTokenAddress: eCommerceHomeTokenTransferrer, + primaryFee: 0, + secondaryFee: 0, + requiredGasLimit: 150_000, + multiHopFallback: address(0) + }) + ); + } + } +} diff --git a/src/MultichainEcommerce/images/image 1.png b/src/MultichainEcommerce/images/image 1.png new file mode 100644 index 00000000..b3a9ea3e Binary files /dev/null and b/src/MultichainEcommerce/images/image 1.png differ diff --git a/src/MultichainEcommerce/images/image 10.png b/src/MultichainEcommerce/images/image 10.png new file mode 100644 index 00000000..5e3bc681 Binary files /dev/null and b/src/MultichainEcommerce/images/image 10.png differ diff --git a/src/MultichainEcommerce/images/image 2.png b/src/MultichainEcommerce/images/image 2.png new file mode 100644 index 00000000..dce5d6bc Binary files /dev/null and b/src/MultichainEcommerce/images/image 2.png differ diff --git a/src/MultichainEcommerce/images/image 3.png b/src/MultichainEcommerce/images/image 3.png new file mode 100644 index 00000000..aafe0876 Binary files /dev/null and b/src/MultichainEcommerce/images/image 3.png differ diff --git a/src/MultichainEcommerce/images/image 4.png b/src/MultichainEcommerce/images/image 4.png new file mode 100644 index 00000000..4dc7d35d Binary files /dev/null and b/src/MultichainEcommerce/images/image 4.png differ diff --git a/src/MultichainEcommerce/images/image 5.png b/src/MultichainEcommerce/images/image 5.png new file mode 100644 index 00000000..37537fdb Binary files /dev/null and b/src/MultichainEcommerce/images/image 5.png differ diff --git a/src/MultichainEcommerce/images/image 6.png b/src/MultichainEcommerce/images/image 6.png new file mode 100644 index 00000000..49f96982 Binary files /dev/null and b/src/MultichainEcommerce/images/image 6.png differ diff --git a/src/MultichainEcommerce/images/image 7.png b/src/MultichainEcommerce/images/image 7.png new file mode 100644 index 00000000..e99969d8 Binary files /dev/null and b/src/MultichainEcommerce/images/image 7.png differ diff --git a/src/MultichainEcommerce/images/image 8.png b/src/MultichainEcommerce/images/image 8.png new file mode 100644 index 00000000..e0cecb4a Binary files /dev/null and b/src/MultichainEcommerce/images/image 8.png differ diff --git a/src/MultichainEcommerce/images/image 9.png b/src/MultichainEcommerce/images/image 9.png new file mode 100644 index 00000000..b4031e33 Binary files /dev/null and b/src/MultichainEcommerce/images/image 9.png differ diff --git a/src/MultichainEcommerce/images/image.png b/src/MultichainEcommerce/images/image.png new file mode 100644 index 00000000..b19734df Binary files /dev/null and b/src/MultichainEcommerce/images/image.png differ diff --git a/src/MultichainEcommerce/interfaces/ICommerceHome.sol b/src/MultichainEcommerce/interfaces/ICommerceHome.sol new file mode 100644 index 00000000..4f1dec8d --- /dev/null +++ b/src/MultichainEcommerce/interfaces/ICommerceHome.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {IProductInput, IProduct} from "./IECommerce.sol"; + +interface ICommerceHome { + //This event refer the successfully buying a product and this data will be processing the front-end app + event ProductsBuy( + uint256 indexed productId, + address indexed buyer, + uint256 price, + address indexed seller, + bytes32 sellerBlockchainID + ); + + //This event refer the successfully adding a product and this data will be processing the front-end app + event ProductAdded(uint256 indexed productId, address indexed sender); + + event PaymentSuccessful( + uint256 indexed productId, address indexed buyer, bytes32 sellerBlockchainId, address indexed seller + ); + event PaymentFailed(uint256 indexed productId, address indexed buyer); + + function addProduct(IProductInput memory _product) external; + + //For checking active remotes + //currently it only operates on 1 remote, but it will be more useful when more chain support comes in the future :) + + function activeRemoteAddress(bytes32 remote) external view returns (address); + + //This function is used to get the details of the requested product id + function getProduct(uint256 id) external view returns (IProduct memory product); + + //Gets all products added by the user whose address is entered (including inactive ones) + function getSellerToProducts(address seller) external view returns (uint256[] memory); +} diff --git a/src/MultichainEcommerce/interfaces/ICommerceRemote.sol b/src/MultichainEcommerce/interfaces/ICommerceRemote.sol new file mode 100644 index 00000000..1bcffe11 --- /dev/null +++ b/src/MultichainEcommerce/interfaces/ICommerceRemote.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +interface ICommerceRemote { + event crossChainProductAdded(address seller); + event crossChainProductBuy(address buyer, uint256 indexed productId); + event crossChainPaymentReceived(address receiver, address buyer, uint256 productId); + event crossChainPaymentFailed(address receiver, address buyer, uint256 productId); + + function crossChainAddProduct(uint256 price, string memory title) external; +} diff --git a/src/MultichainEcommerce/interfaces/IECommerce.sol b/src/MultichainEcommerce/interfaces/IECommerce.sol new file mode 100644 index 00000000..7aef3d9a --- /dev/null +++ b/src/MultichainEcommerce/interfaces/IECommerce.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +enum ProductStatus { + ACTIVE, + SOLD, + PENDING +} + +struct IProduct { + address seller; + uint256 price; + ProductStatus status; + address buyer; + string title; + bytes32 sellerBlockchainId; + uint256 pendingDeadline; +} + +struct ICrossChainPaymentResult { + uint256 productId; + bool success; + address buyer; +} + +struct ICrossChainPayment { + address receiverAddress; + uint256 productId; + address buyer; +} + +struct IProductInput { + uint256 price; + string title; +} + +struct ICrossChainReceiver { + address sellerAddress; + bytes32 sellerBlockchainId; + uint256 value; +} + +enum CommerceMessageType { + ADD_PRODUCT, + PURCHASE, + PAYMENT_RESULT +} + +struct ICommerceMessage { + CommerceMessageType message_type; + address client; + bytes payload; +} + +struct ITokenSentMessage { + address buyer; + uint256 productId; +} + +interface IECommerce {} diff --git a/src/MultichainEcommerce/interfaces/IERC20CommerceHome.sol b/src/MultichainEcommerce/interfaces/IERC20CommerceHome.sol new file mode 100644 index 00000000..adfbfe46 --- /dev/null +++ b/src/MultichainEcommerce/interfaces/IERC20CommerceHome.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {ICommerceHome} from "./ICommerceHome.sol"; + +interface IERC20CommerceHome is ICommerceHome { + //Buy product with home chain + //@Params _product refer the client product input + function buyProduct(uint256 _productId, uint256 amount) external; +} diff --git a/src/MultichainEcommerce/interfaces/IERC20CommerceRemote.sol b/src/MultichainEcommerce/interfaces/IERC20CommerceRemote.sol new file mode 100644 index 00000000..b97eb811 --- /dev/null +++ b/src/MultichainEcommerce/interfaces/IERC20CommerceRemote.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {ICommerceRemote} from "./ICommerceRemote.sol"; + +interface IERC20CommerceRemote is ICommerceRemote { + function crossChainBuyProduct(uint256 productId, uint256 value) external; +} diff --git a/src/MultichainEcommerce/interfaces/INativeCommerceHome.sol b/src/MultichainEcommerce/interfaces/INativeCommerceHome.sol new file mode 100644 index 00000000..475fbf5f --- /dev/null +++ b/src/MultichainEcommerce/interfaces/INativeCommerceHome.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {IProductInput, ProductStatus} from "./IEcommerce.sol"; +import {ICommerceHome} from "./ICommerceHome.sol"; + +interface INativeCommerceHome is ICommerceHome { + function buyProduct(uint256 _productId) external payable; +} diff --git a/src/MultichainEcommerce/interfaces/INativeCommerceRemote.sol b/src/MultichainEcommerce/interfaces/INativeCommerceRemote.sol new file mode 100644 index 00000000..7e878ea7 --- /dev/null +++ b/src/MultichainEcommerce/interfaces/INativeCommerceRemote.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Ecosystem +pragma solidity ^ 0.8.18; + +import {ICommerceRemote} from "./ICommerceRemote.sol"; + +interface INativeCommerceRemote is ICommerceRemote { + function crossChainBuyProduct(uint256 productId) external payable; +}