Skip to content

Commit

Permalink
Update Solana gateway docs (#480)
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev authored Oct 10, 2024
1 parent 3e01d68 commit 93464d6
Showing 1 changed file with 251 additions and 6 deletions.
257 changes: 251 additions & 6 deletions src/pages/developers/chains/solana.mdx
Original file line number Diff line number Diff line change
@@ -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<Deposit>, amount: u64, memo: Vec<u8>) -> 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<u8> = 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`.

0 comments on commit 93464d6

Please sign in to comment.