From 399d4636d739c522fe6a996caa14738b20ea9e61 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 1 Oct 2024 13:14:42 +0300 Subject: [PATCH] Update Solana gateway docs --- src/pages/developers/chains/solana.mdx | 257 ++++++++++++++++++++++++- 1 file changed, 251 insertions(+), 6 deletions(-) diff --git a/src/pages/developers/chains/solana.mdx b/src/pages/developers/chains/solana.mdx index 3c2b2ab5..12acc813 100644 --- a/src/pages/developers/chains/solana.mdx +++ b/src/pages/developers/chains/solana.mdx @@ -1,9 +1,254 @@ -On Solana the gateway is implemented as a Solana program. +To interact with universal applications from Solana, use the Solana Gateway. The +Solana Gateway allows you to deposit SOL (the native gas token of Solana) to an +externally-owned account (EOA) or a universal application on ZetaChain. You can +also deposit SOL and call a universal application in a single transaction using +the same `deposit` instruction. -Solana gateway supports: +**Note:** In the next version of the Solana Gateway, the `deposit` and +`deposit_and_call` functionalities will be separate functions. -- depositing SOL to a universal app or an account on ZetaChain -- depositing SOL and calling a universal app -- depositing SPL tokens (coming soon) +## Deposit SOL -https://github.com/zeta-chain/protocol-contracts-solana/ +To deposit SOL to an EOA or a universal application on ZetaChain, use the +`deposit` instruction of the Solana Gateway program. + +```rust +pub fn deposit(ctx: Context, amount: u64, memo: Vec) -> Result<()> +``` + +### Parameters + +- `amount`: The amount of SOL (in lamports) to deposit. +- `memo`: A vector of bytes containing the receiver's address and an optional + payload. + +### Memo Format + +- **Minimum Length:** The `memo` must be at least 20 bytes long. +- **Maximum Length:** The `memo` must not exceed 512 bytes. +- **Structure:** + - **First 20 Bytes:** Receiver's address on ZetaChain (similar to an Ethereum + address). + - **Remaining Bytes (Optional):** Payload to be sent to the universal + application. + +### Usage + +When you call the `deposit` instruction, the specified amount of SOL is +transferred from your account to the Solana Gateway's Program Derived Account +(PDA). The `memo` parameter is used to specify the receiver's address and an +optional message. If the `memo` contains only the receiver's address (20 bytes), +the SOL will be deposited to the receiver without triggering a contract call. If +the `memo` contains additional data beyond the 20-byte address, it will initiate +a cross-chain call to the universal application with the provided payload. + +**Example of Depositing SOL to an EOA:** + +```rust +let receiver_address: [u8; 20] = [/* receiver's ZetaChain address */]; +let amount_in_lamports: u64 = 1_000_000; // Amount in lamports (1 SOL = 1,000,000,000 lamports) + +// Memo consists of only the receiver's address +let memo = receiver_address.to_vec(); + +gateway::deposit( + ctx, + amount_in_lamports, + memo, +)?; +``` + +**Example of Depositing SOL and Calling a Universal Application:** + +```rust +let receiver_address: [u8; 20] = [/* universal application's ZetaChain address */]; +let amount_in_lamports: u64 = 1_000_000; // Amount in lamports +let payload: Vec = b"Hello, ZetaChain!".to_vec(); + +// Memo consists of the receiver's address followed by the payload +let mut memo = receiver_address.to_vec(); +memo.extend_from_slice(&payload); + +gateway::deposit( + ctx, + amount_in_lamports, + memo, +)?; +``` + +### Notes + +- The `receiver` is specified in the first 20 bytes of the `memo`. +- If the `memo` length is exactly 20 bytes (only the receiver's address), + depositing SOL will **not** trigger a contract call. +- If the `memo` length is greater than 20 bytes, depositing SOL will **trigger** + a cross-chain call to the universal application with the provided payload. +- After the deposit is processed, the receiver gets the ZRC-20 version of the + deposited SOL (e.g., ZRC-20 SOL). +- The `memo` must be at least 20 bytes (to include the receiver's address) and + at most 512 bytes. + +## Calling `deposit` from the Frontend + +To interact with the Solana Gateway from a frontend application, you can refer +to the [solanaDeposit function in the ZetaChain +Toolkit](https://github.com/zeta-chain/toolkit/blob/main/packages/client/src/solanaDeposit.ts). +This function demonstrates how to call the `deposit` instruction from the +frontend using Anchor and the Solana Web3.js library. + +**High-Level Steps:** + +1. **Load the User's Keypair:** + + Load the user's Solana keypair to sign transactions. + + ```typescript + const keypair = await getKeypairFromFile(args.idPath); + const wallet = new anchor.Wallet(keypair); + ``` + +2. **Set Up the Connection and Provider:** + + Establish a connection to the Solana cluster and set up the Anchor provider. + + ```typescript + const connection = new anchor.web3.Connection(args.api); + const provider = new anchor.AnchorProvider(connection, wallet, anchor.AnchorProvider.defaultOptions()); + anchor.setProvider(provider); + ``` + +3. **Load the Gateway Program:** + + Load the Gateway program using its IDL and program ID. + + ```typescript + const programId = new anchor.web3.PublicKey(Gateway_IDL.address); + const gatewayProgram = new anchor.Program(Gateway_IDL as anchor.Idl, programId, provider); + ``` + +4. **Calculate the Deposit Amount:** + + Convert the amount of SOL to lamports. + + ```typescript + const depositAmount = new anchor.BN(anchor.web3.LAMPORTS_PER_SOL * args.amount); + ``` + +5. **Prepare the Memo:** + + - **Recipient Address:** Convert the recipient's ZetaChain address to a + buffer. + + ```typescript + const recipientBuffer = Buffer.from(args.recipient.slice(2), "hex"); + ``` + + - **Message Formatting:** If there are additional parameters, encode them + using ABI encoding. + + ```typescript + const encodedParams = ethers.utils.defaultAbiCoder.encode(args.params[0], args.params[1]); + const paramsBuffer = Buffer.from(encodedParams.slice(2), "hex"); + ``` + + - **Combine Recipient and Parameters:** + + ```typescript + const memo = Buffer.concat([recipientBuffer, paramsBuffer]); + ``` + +6. **Create and Send the Transaction:** + + Create the `deposit` instruction and send the transaction. + + ```typescript + const depositInstruction = await gatewayProgram.methods + .deposit(depositAmount, memo) + .accounts({ + pda: pdaAccount, + signer: wallet.publicKey, + systemProgram: anchor.web3.SystemProgram.programId, + }) + .instruction(); + + const tx = new anchor.web3.Transaction().add(depositInstruction); + + const txSignature = await anchor.web3.sendAndConfirmTransaction(connection, tx, [keypair]); + + console.log("Transaction signature:", txSignature); + ``` + +**Note:** The full code and implementation details can be found in the +[ZetaChain Toolkit +repository](https://github.com/zeta-chain/toolkit/blob/main/packages/client/src/solanaDeposit.ts). + +### Recommendation on Message Formatting + +We recommend formatting the message payload using ABI encoding so that it can be +easily decoded in a universal application on ZetaChain. ABI encoding ensures +compatibility and standardization when transmitting data across different +platforms. + +**Example of ABI Encoding:** + +```typescript +const ethers = require("ethers"); + +// Define the parameter types and values +const paramTypes = ["uint256", "string"]; +const paramValues = [12345, "Hello, ZetaChain!"]; + +// Encode the parameters +const encodedParams = ethers.utils.defaultAbiCoder.encode(paramTypes, paramValues); + +// Convert to Buffer or Uint8Array as needed +const paramsBuffer = Buffer.from(encodedParams.slice(2), "hex"); // Remove '0x' prefix +``` + +## Additional Information + +- **Lamports and SOL:** 1 SOL equals 1,000,000,000 lamports. Ensure you convert + SOL amounts to lamports when specifying the `amount` parameter. +- **Address Format:** The receiver's address is specified in the first 20 bytes + of the `memo`, consistent with Ethereum-style addresses used on ZetaChain. +- **Program Derived Account (PDA):** The PDA is a special account used by the + Solana Gateway program to manage deposited funds securely. + +## Future Support + +- **Separate `deposit` and `deposit_and_call` Functions:** In the next version + of the Solana Gateway, the `deposit` and `deposit_and_call` functionalities + will be separate functions to improve clarity and usability. +- **SPL Tokens:** Support for SPL tokens (Solana's native token standard) is + coming soon. This will allow you to deposit SPL tokens and interact with + universal applications on ZetaChain using these tokens. +- **Calling Solana Programs from Universal Applications:** In the future, + universal applications on ZetaChain will be able to call Solana programs + directly, enabling more complex cross-chain interactions. + +## Error Handling + +The Solana Gateway program includes several error codes to handle different +failure scenarios: + +- `SignerIsNotAuthority`: The signer is not authorized to perform the action. +- `DepositPaused`: Deposits are currently paused. +- `MemoLengthTooShort`: The `memo` payload is less than the minimum required + length of 20 bytes. +- `MemoLengthExceeded`: The `memo` payload exceeds the maximum allowed length of + 512 bytes. + +Ensure to handle these errors appropriately in your application. + +## Revert Transactions + +The Solana Gateway supports transaction reversion in case of failures. If a +cross-chain call fails on the ZetaChain side, the deposited SOL will be reverted +back to the original sender on Solana. + +## Conclusion + +The Solana Gateway provides a seamless way to interact with universal +applications on ZetaChain from Solana. By using the `deposit` instruction, you +can deposit SOL and optionally trigger cross-chain contract calls to universal +applications on ZetaChain by including a payload in the `memo`.