From 2c9b334af5e7a219ec7a3650fb3c7f8419ee2560 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 5 Oct 2022 11:33:01 -0500 Subject: [PATCH] xmint: evm documentation --- src/projects/xmint/client.md | 28 +++++--- src/projects/xmint/overview.md | 2 +- src/projects/xmint/xMintEVM.md | 125 +++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 9 deletions(-) diff --git a/src/projects/xmint/client.md b/src/projects/xmint/client.md index acc13d7..7135a53 100644 --- a/src/projects/xmint/client.md +++ b/src/projects/xmint/client.md @@ -17,17 +17,29 @@ Compiles and deploys the contracts using the chain appropriate tools. The deploy For EVM, this is done using [forge](https://getfoundry.sh) and for Solana, this is done using [Anchor](https://www.anchor-lang.com/). ## Register App -Takes the deployed contract address from the target chain and registers it on the source chain. No Wormhole interaction is necessary for this step. - -Takes the deployed token address from the target chain and attests it on the source chain. A Wormhole token attestation interaction is necessary for this step. - +Initiate a two step process of: +1. Register deployed contract address from target chain onto source chain + - no Wormhole interaction is necessary for this step +2. Attest deployed token address from target chain onto source chain + - Wormhole token attestation interaction is necessary for this step ## Buy Token - +Initiates a three step process of: +1. Create a buy VAA on source chain + - Emits a Contract Controlled Payload that contains (1) the amount of tokens the user wants to pay and (2) the user's wallet address. + +2. Submit buy VAA on target chain and generate a VAA to claim tokens + - Verifies the buy VAA generated in the previous step, mints the appropriate amount of target chain tokens, and generates a Token Transfer VAA that sends the minted amount of tokens to the user's wallet on source chain. + +3. Claim tokens on source chain + - Verifies the Token Transfer VAA generated in the previous step to claim a wrapped version of the token on the source chain. ## Sell Token +Initiates a three-step process of: +1. Create a sell VAA on source chain +2. Submit sell VAA on target chain and generate a VAA to claim tokens +3. Claim tokens on source chain - - -## Balance \ No newline at end of file +## Balance +Returns the balance of a token by chain in question and chain token originated from. \ No newline at end of file diff --git a/src/projects/xmint/overview.md b/src/projects/xmint/overview.md index c70261f..d9afaa1 100644 --- a/src/projects/xmint/overview.md +++ b/src/projects/xmint/overview.md @@ -34,4 +34,4 @@ Orchestrator is a ts client that takes arguments from the command line to call v ### xdapp.config.json -This maintains some constants about the chains RPC endpoints, private keys used to deploy code, etc. It also includes the Wormhole RPC endpoint. \ No newline at end of file +This maintains some constants about the chains RPC endpoints, private keys used to deploy code, deployed contract addresses, etc. It also includes the Wormhole RPC endpoint. \ No newline at end of file diff --git a/src/projects/xmint/xMintEVM.md b/src/projects/xmint/xMintEVM.md index e69de29..c7c4d5d 100644 --- a/src/projects/xmint/xMintEVM.md +++ b/src/projects/xmint/xMintEVM.md @@ -0,0 +1,125 @@ +# xMint.sol + +xMint.sol is an application contract on EVM capable of communicating with the Wormhole Core Bridge and Token Bridge. + +Start by initializing key contract state variables for the application. + +```solidity + +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "./Wormhole/IWormhole.sol"; +import "./Wormhole/ITokenBridge.sol"; +import "./Wormhole/BridgeStructs.sol"; +import "solidity-bytes-utils/BytesLib.sol"; + +contract Xmint is ERC20 { + using BytesLib for bytes; + + mapping(uint16 => bytes32) _applicationContracts; + mapping(bytes32 => bool) _completedMessages; + address owner; + IWormhole core_bridge; + ITokenBridge token_bridge; + uint32 nonce = 0; + event Log(string indexed str); + +``` + +## Constructor +This sets the owner of the contract to the deployer and initializes interfaces for the Wormhole Core Bridge and Token Bridge. + +```solidity + +constructor( + string memory name_, + string memory symbol_, + address coreBridgeAddress, + address tokenBridgeAddress +) ERC20(name_, symbol_) { + owner = msg.sender; + core_bridge = IWormhole(coreBridgeAddress); + token_bridge = ITokenBridge(tokenBridgeAddress); +} + +``` + +## RegisterApplicationContracts +It's typically a good idea to register and track the contracts from foreign chains that you're accepting VAAs from, as anyone could deploy a contract and generate a fake VAA that looks like a real VAA you'd want to accept. + +```solidity + +/** + Registers it's sibling applications on other chains as the only ones that can send this instance messages + */ +function registerApplicationContracts(uint16 chainId, bytes32 applicationAddr) public { + require(msg.sender == owner, "Only owner can register new chains!"); + _applicationContracts[chainId] = applicationAddr; +} + +``` + +## SubmitForeignPurchase +This takes in a bytes payload and calls the Wormhole Token Bridge to receive the bridged tokens, mint the corresponding amount of native token, and calls the Wormhole Token Bridge to send the newly minted tokens back to the user. + +The `completeTransferWithPayload()` function of the token bridge takes one argument: +- encodedVm: The unverified and unparsed message that is generated by the Guardian Network + +The `transferTokens()` function of the token bridge takes six arguments: +- Token: contract address of the token +- Amount: amount of tokens to transfer +- RecipientChain: ChainID of the target chain +- Recipient: address for target wallet +- ArbiterFee: amount of tokens the user is willing to pay as relayer fee +- Nonce: A number to uniquely identify this message, optionally used for batching when multiple messages are generated by the same transaction. See [here](../../technical/evm/coreLayer.md) for more details. + +```solidity + +/** + Takes inventory of the foreign currency + Mints tokens to self + Transfers tokens with Payload 1 to Receipient on Foreign chain + */ +function submitForeignPurchase(bytes memory encodedVm) public returns (uint64) { + // Complete transfer will give the Tokens to this Contract + // Unlike solana, we don't need to check that the emitter is a Portal contract as register_ scripts register all the Portal contracts + // and the completeTransfer function checks the emitter is a valid Portal contract on one of the chains it's registered with + BridgeStructs.TransferWithPayload memory vaa = _decodePayload(token_bridge.completeTransferWithPayload(encodedVm)); + // Mint tokens to this contract + //amt they paid is NATIVE + //multiply by 100 to get how many tokens to give out + uint256 amtToMint = vaa.amount * 100; + _mint(address(this), amtToMint); + // Give Token Bridge allowance to take tokens from this contract + this.approve(address(token_bridge), amtToMint); + // Transfer tokens via Token Bridge over to Recipient in payload + uint64 sequence = token_bridge.transferTokens(address(this), amtToMint, vaa.tokenChain, bytes32(vaa.payload), 0, nonce); + nonce += 1; + return sequence; +} + +``` + +## _decodePayload +This helper function takes the set of bytes returned by the token bridge and decodes it into the more useful form of a `TransferWithPayload` struct. + +```solidity + +function _decodePayload(bytes memory payload) internal pure returns (BridgeStructs.TransferWithPayload memory) { + BridgeStructs.TransferWithPayload memory decoded = BridgeStructs.TransferWithPayload({ + payloadID: payload.slice(0,1).toUint8(0), + amount: payload.slice(1,32).toUint256(0), + tokenAddress: payload.slice(33,32).toBytes32(0), + tokenChain: payload.slice(65,2).toUint16(0), + to: payload.slice(67,32).toBytes32(0), + toChain: payload.slice(99,2).toUint16(0), + fromAddress: payload.slice(101,32).toBytes32(0), + payload: payload.slice(133, payload.length-133) + }); + + return decoded; + } + +``` \ No newline at end of file