Skip to content

Commit

Permalink
Merge pull request #33 from dpowxconsensus/testnet-docs
Browse files Browse the repository at this point in the history
add solana gateway doc
  • Loading branch information
vatsalgupta13 authored Sep 11, 2024
2 parents 2331bcd + 84583fa commit ae9dd9b
Show file tree
Hide file tree
Showing 13 changed files with 631 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Solana Guides
sidebar_position: 1
---

import {
HomepageCard as Card,
HomepageSection as Section,
} from '../../../../src/components/HomepageComponents';

This section will cover how the crosschain framework can be used for Solana contracts to build iDapps. It provides the details around various functions and how they can be implemented using some sample contracts.

<Section title="Theoretical Concepts" id="web-sdks">
<Card
title="iDapp Functions"
description="Understand the various functions Crosstalk provides to create your iDapp."
to="solana-guides/iDapp-functions"
/>
<Card
title="Additional Security Module"
description="How iDapps can use ASM to add another layer of security as required."
to="solana-guides/asm-implementation"
/>
</Section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Solana Guides",
"position":5
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Args Accounts

The Args Accounts are used to store temporary function arguments, helping to avoid passing them directly into functions. This prevents reaching transaction limits and ensures the transaction is processed smoothly.



Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Args Accounts",
"position": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
---
title: packet_account
sidebar_position: 1
---

## Packet Account

The Packet Account is used to store request packet information or messages that need to be delivered to the `i_receive` or `i_ack` functions of the Gateway contract.


### Packet Account Structure:

The Packet Account is serialized as follows:

1. `[0..32] - Creator`: The first 32 bytes represent the account creator.
2. `[33] - Blocked Status`: The 33rd byte indicates whether the account is blocked or not.
If the account is blocked, it can only be deleted.
3. `[34..37] - Packet Length`: Bytes 34 to 37 contain the length of the packet in little-endian format.
4. `[38..(37 + packet_length)] - Packet Data`: Starting from byte 38, the packet data is stored. The length of the data is determined by the packet_length field.

### Prefix:

```rust
const PACKET_SEED_PREFIX: &[u8] = b"PA_";
```

### Instructions:


1. `initialize_packet_account`

```rust
pub fn initialize_packet_account(
ctx: Context<InitializePacketAccount>,
seed: Vec<u8>,
packet: Option<Vec<u8>>,
) -> Result<()>
```

##### Description:
* Initializes a new Packet Account. The seed is used to generate a unique PDA (Program Derived Address), and an optional packet can be included. If no packet is passed, the packet length is set to 0.

##### Cost:
* Approximately `0.07216128 SOL`, which can be reclaimed upon deletion of the account. Only the creator of the account can delete it.

##### Parameters:

* `seed`: A unique identifier to generate the PDA.
* `packet`: Optional packet data. If None, the packet length is 0.

##### Account Context:

```rust
#[derive(Accounts)]
#[instruction(seed: Vec<u8>)]
pub struct InitializePacketAccount<'info> {
#[account(
init,
payer=signer,
seeds=[
PACKET_SEED_PREFIX,
&seed
],
bump,
space= PacketAccount::SIZE
)]
pub packet_account: AccountLoader<'info, PacketAccount>,
#[account(mut)]
pub signer: Signer<'info>,
pub system_program: Program<'info, System>,
}
```

<br/>
<hr/>
<br/>


2. `append_packet_account`

```rust
pub fn append_packet_account(
ctx: Context<UpdatePacketAccount>,
seed: Vec<u8>,
packet: Vec<u8>,
) -> Result<()>
```

##### Description:
* Appends additional data to an existing Packet Account. The seed used during initialization must be provided to locate the correct account.

##### Parameters:

* `seed`: The same seed used when initializing the Packet Account.
* `packet`: The data to append to the existing packet account.

##### Account Context:

```rust
#[derive(Accounts)]
#[instruction(seed: Vec<u8>)]
pub struct UpdatePacketAccount<'info> {
#[account(
mut,
seeds=[PACKET_SEED_PREFIX, &seed],
bump,
)]
pub packet_account: AccountLoader<'info, PacketAccount>,
#[account()]
pub signer: Signer<'info>,
}
```
<br/>
<hr/>
<br/>

3. `update_packet_account`

```rust
pub fn update_packet_account(
ctx: Context<UpdatePacketAccount>,
seed: Vec<u8>,
slice: Vec<u8>,
from: u64,
to: u64,
) -> Result<()>
```

##### Description:
* Updates a portion of the packet data in an existing Packet Account, replacing the data from index `from` to `to`.


##### Parameters:

* `seed`: The same seed used during initialization.
* `slice`: The data to replace the existing packet content.
* `from`: The starting index of the data to replace.
* `to`: The ending index of the data to replace.

<br/>
<hr/>
<br/>


4. `update_packet_creator`

```rust
pub fn update_packet_creator(
ctx: Context<UpdatePacketAccount>,
seed: Vec<u8>,
new_owner: Pubkey,
) -> Result<()>
```

##### Description:
* Allows the creator of the Packet Account to transfer ownership to a new public key (`new_owner`).

##### Parameters:
* `seed`: The same seed used during initialization.
* `new_owner`: The new owner (`public key`) of the packet.

<br/>
<hr/>
<br/>

5. `delete_packet_account`

```rust
pub fn delete_packet_account(
_ctx: Context<DeletePacketAccount>,
_seed: Vec<u8>
) -> Result<()>
```

##### Description:
* Deletes the Packet Account and refunds the remaining SOL back to the signer. Only the original creator of the account can perform this operation.

##### Parameters:
* `seed`: The same seed used during initialization.


##### Account Context:

```rust
#[derive(Accounts)]
#[instruction(seed: Vec<u8>)]
pub struct DeletePacketAccount<'info> {
#[account(
mut,
seeds=[PACKET_SEED_PREFIX, &seed],
bump,
constraint = packet_account.load()?.get_creator() == signer.key() @GatewayError::OnlyCreator,
close = signer
)]
pub packet_account: AccountLoader<'info, PacketAccount>,
#[account(mut)]
pub signer: Signer<'info>,
}
```
<br/>
<hr/>


Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: ASM Implementation
sidebar_position: 1
---

:::info
To understand how Router ASM works, refer to this [link](../../message-transfer-via-crosstalk/key-concepts/additional-security-modules#how-does-an-asm-work).
:::

The function `verify_cross_chain_request` enhances security for a specific cross-chain flow.

When a request is received on the destination chain, the `verify_cross_chain_request` function is invoked on the specified ASM (Application Security Module) address before executing the user's contract calls. The ASM can return either `true` or `false` to instantly validate or invalidate the request. If further time is needed for validation, the ASM can revert the request.

If the function returns `true`, the execution of the user contract calls will proceed. If it returns `false`, the contract calls will be skipped. Should the ASM implementation revert the request, the transaction will be rolled back, and no state changes will occur on the Gateway.

The ASM module can continue to revert requests until it can confidently validate or invalidate them. This ensures that application-level validation is completed before any cross-chain request is executed on the Gateway contract and sent to the destination contract.


```javascript
pub fn verify_cross_chain_request(
ctx: Context<VerifyCrossChainRequest>,
request_identifier: u128,
request_timestamp: u128,
request_sender: String,
src_chain_id: String,
handler_program_pub_key: Pubkey,
handler_account_pub_key: Pubkey,
) -> Result<bool>
```

In this function selector, there are 6 arguments. Within this function, any possible business logic or validation can be added using these arguments. Each argument has its own purpose in the `verify_cross_chain_request` request:

##### Parameters:

* `request_identifier`: A unique identifier of the request. It is added by the source chain's Gateway contract.
* `request_timestamp`: Timestamp when a request is added/verified on the Router Chain.
* `request_sender`: The address of the application's contract on the source chain, represented as a string.
* `src_chain_id`: The chain ID of the src chain, in string format.
* `handler_program_pub_key`: The program ID for which this request is intended.
* `handler_account_pub_key`: The program-derived account for the current handler program.

#### Account Context
```rust
#[derive(Accounts)]
pub struct VerifyCrossChainRequest<'info> {
//CHECK: asm can have different storage structure, asm have to validate account
#[account(mut)]
pub asm_account: UncheckedAccount<'info>,
// it is passed so that asm contract can validate if it is signed by authorised program id
#[account()]
pub gateway_authority: Signer<'info>,
pub system_program: Program<'info, System>,
//NOTE: all remaining account will be passed as well
}
```

`Security Note:` Since this function can be called from the Gateway contract only, it must validate `gateway_authority` with expected signer.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "ASM Implementation",
"position": 4
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Solana iDapp Functions

Cross-chain message transmission on the Solana chain is enabled through the `i_send` function in Router's Gateway contract. When initiating a cross-chain request, developers can invoke this function, passing the required parameters along with the payload that needs to be transferred from the source chain to the destination chain.

To ensure successful cross-chain communication, Solana iDapp developers must also implement the following essential functions within their contracts:
1. `i_receive`: This function must be included on the destination chain to handle incoming cross-chain requests.
2. `i_ack`: Implement this function to process acknowledgment of requests on the source chain, particularly when cross-chain acknowledgment is required.
3. `set_dapp_metadata`: This function is necessary to designate a fee_payer for executing cross-chain requests. Without setting this, requests will remain in a blocked state on the Router Chain.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "iDapp Functions",
"position": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
title: i_ack
sidebar_position: 4
---

After the `i_receive` function is executed, an acknowledgment is generated by Router's destination chain Gateway contract, indicating whether the call was successful. The i_ack function must be implemented in your contract with the following structure:

```rust
pub fn i_ack(
ctx: Context<IAck>,
request_identifier: u128,
exec_flag: bool,
) -> Result<Vec<u8>>
```

#### Parameters:
* `request_identifier`: This is the same nonce received when calling the `i_send` function on the source chain's Gateway contract. It helps map the acknowledgment to the corresponding request.
* `src_chain_id`: A boolean value indicating the execution status of the request on the destination chain.

#### Account Context
```rust
#[derive(Accounts)]
pub struct IAck<'info> {
//CHECK: dapp can have different storage structure, dapp have to validate account
#[account(mut)]
pub dapp_account: UncheckedAccount<'info>,
#[account()]
pub packet_account: AccountLoader<'info, PacketAccount>,
#[account()]
pub gateway_authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
```

#### Account Info:
* `packet_account`: Contains the exec data which is the data in bytes that provides the abi-encoded return value from the `i_receive` call on the destination chain. Based on the application's requirement, this data can be decoded and processed on the source chain.
* `gateway_authority`: The authorized signer by the Gateway contract to ensure the request is valid.

:::caution
Currently, `i_ack` does not support dynamically passing additional accounts beyond those explicitly listed in the IAck context.
:::
Loading

0 comments on commit ae9dd9b

Please sign in to comment.