-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
251 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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`. |