Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add script to compute gateway limits #197

Merged
merged 17 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eight-candles-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@axelar-network/axelar-cgp-sui': minor
---

Removed remote decimals tracking from ITS as it will be handled at the hub.
53 changes: 53 additions & 0 deletions .github/workflows/limits.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Find Limits

on: pull_request
Foivos marked this conversation as resolved.
Show resolved Hide resolved

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
limits:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup tools
uses: ./.github/actions/setup-tools
with:
install-sui: 'true'
install-nodejs: 'true'

- name: Build TS and Move Modules
run: npm run build

- name: Initialize Sui Config
run: echo -e "y\n\n1" | sui client envs

- name: Run Localnet
run: nohup sh -c "RUST_LOG="off,sui_node=info" sui start --with-faucet --force-regenesis" > nohup.out 2> nohup.err < /dev/null &

- name: Sleep for 30 seconds
run: sleep 30s
shell: bash

- name: Create limits
run: node scripts/limits.js >> comment.md

- name: Find Code Coverage comment
uses: peter-evans/find-comment@v3
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: Code Coverage Summary

- name: Create or update Code Coverage comment
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: ./comment.md
edit-mode: replace
68 changes: 68 additions & 0 deletions INTEGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Sui Axelar Gateway and ITS Integration
Foivos marked this conversation as resolved.
Show resolved Hide resolved

Sui is a smart contract chain that offers some unique design parameters. For this reason there have been a few differences between the implementation of smart contracts on Sui compared to EVM chains, that are used as reference

## General Limitations

### Design Limitation

There are quite a few differences between EVM and Sui.

In Sui, there are packages and modules that can run code, similar to EVM smart contracts. A big difference however is that Sui packages/modules do not have any storage available. Storage as a concept only exists on objects, which can be defined and controlled by modules. To access and modify any storage the corresponding object needs to be available. This means that conventional EVM smart contracts effectively combine the functionality of modules and objects in Sui.

Additionally there is a lack of interfaces whatsoever. It is impossible for a module to ever call another module that is published at a later time. This means applications that want to interface with future applications must be called by those future applications, but need to only call pre-existing ones. To expand on this, we expect contract calls that are received to potentially modify the storage of multiple objects in a single call, which makes it impossible to require modules to implement a 'standardized' function that a relayer will call, because the number of arguments required varies depending on the application (or the type of call).

Package "upgrades" result in a new, upgraded package being created, while preserving the old package. This new package can modify objects created by the old package, but any external modules that are using the old package will continued to do so, until they are upgraded too. This means that maintaining packages that depend on multiple existing packages is quite difficult if the dependancies are expected to upgrade.

Finally, we do not want to require the payload of incoming calls to have a certain format, because that would mean that working applications that want to exapnd to Sui need to redesign their working protocoll to accomodate Sui, discouraging them from doing so.

### Basic Limitations

See [this doc](https://move-book.com/guides/building-against-limits.html) for reference. The gas limit for sui is 50 SUI, which is over 100 times larger than any transaction needed for this context. There is also a transaction size limit of 128KB. Objects cannot be more than 256KB in size and there cannot be more than 1024 dynamic fields created on an object on a single transaction. See below for how these limitations affect potential designs.

## Axelar Gateway

The Axelar gateway is the remote interface for the Axelar Network to interract with any given chain. The reference implementation for such a smart contract can be found [here](https://github.com/axelarnetwork/axelar-cgp-solidity), with some design requirements found specifically [here](https://github.com/axelarnetwork/axelar-gmp-sdk-solidity/blob/main/contracts/gateway/INTEGRATION.md)

The Sui message sending looks like this

```mermaid
flowchart LR
User(User)
SG[Source Gateway]
MT[(MessageTicket)]

User -->|prepare_message| SG --> MT --> |send_message| SG
SG -.->|ContractCall event| SG
SG -->|Confirm event| AXL
```

Receiving calls looks like this (see below for relayer discovery)

```mermaid
flowchart LR
DG[Destination Gateway]
RD[Relayer Discovery]
AXL{Axelar Amplifier}
Contract[Destination contract]
Transaction[(Transaction)]

AXL -->|approve_messages| DG
Relayer -->|consume_approved_message| DG --> |ApprovedMessage| Transaction
Relayer -->|get_transaction| RD --> Transaction --> Contract
```

The verifier/signer rotation flow looks like the following:

```mermaid
flowchart LR
AXL{Axelar Amplifier}
DG[Destination Gateway]

AXL -.->|Verifier set change| AXL
AXL -->|rotate_signers| DG
DG -.->|SignersRotated event| DG
DG --->|Confirm event| AXL
```
## Relayer Discovery

1 change: 0 additions & 1 deletion move/example/sources/its/its.move
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ public fun register_coin<TOKEN>(
coin_metadata.get_name(),
coin_metadata.get_symbol(),
coin_metadata.get_decimals(),
coin_metadata.get_decimals(),
);
let coin_management = coin_management::new_locked();

Expand Down
8 changes: 4 additions & 4 deletions move/its/sources/events.move
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public struct InterchainTransfer<phantom T> has copy, drop {
source_address: address,
destination_chain: String,
destination_address: vector<u8>,
amount: u256,
amount: u64,
data_hash: Bytes32,
}

Expand All @@ -38,7 +38,7 @@ public struct InterchainTransferReceived<phantom T> has copy, drop {
source_chain: String,
source_address: vector<u8>,
destination_address: address,
amount: u256,
amount: u64,
data_hash: Bytes32,
}

Expand All @@ -62,7 +62,7 @@ public(package) fun interchain_transfer<T>(
source_address: address,
destination_chain: String,
destination_address: vector<u8>,
amount: u256,
amount: u64,
data: &vector<u8>,
) {
let data_hash = bytes32::new(address::from_bytes(keccak256(data)));
Expand Down Expand Up @@ -98,7 +98,7 @@ public(package) fun interchain_transfer_received<T>(
source_chain: String,
source_address: vector<u8>,
destination_address: address,
amount: u256,
amount: u64,
data: &vector<u8>,
) {
let data_hash = bytes32::new(address::from_bytes(keccak256(data)));
Expand Down
28 changes: 4 additions & 24 deletions move/its/sources/its.move
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,6 @@ const MESSAGE_TYPE_DEPLOY_INTERCHAIN_TOKEN: u256 = 1;
#[test_only]
const ITS_HUB_ROUTING_IDENTIFIER: vector<u8> = b"hub";

// === The maximum number of decimals allowed ===
#[test_only]
const DECIMALS_CAP: u8 = 9;

#[test_only]
public fun create_for_testing(ctx: &mut TxContext): ITS {
let mut version_control = version_control();
Expand Down Expand Up @@ -416,7 +412,6 @@ fun test_register_coin() {
string::utf8(b"Name"),
ascii::string(b"Symbol"),
10,
12,
);
let coin_management = its::coin_management::new_locked();

Expand All @@ -432,13 +427,11 @@ fun test_deploy_remote_interchain_token() {
let token_name = string::utf8(b"Name");
let token_symbol = ascii::string(b"Symbol");
let token_decimals = 10;
let remote_decimals = 12;

let coin_info = its::coin_info::from_info<COIN>(
token_name,
token_symbol,
token_decimals,
remote_decimals,
);
let coin_management = its::coin_management::new_locked();

Expand Down Expand Up @@ -483,9 +476,7 @@ fun test_deploy_interchain_token() {
string::utf8(b"Name"),
ascii::string(b"Symbol"),
10,
12,
);
let scaling = coin_info.scaling();
let coin_management = its::coin_management::new_locked();

let token_id = register_coin(&mut its, coin_info, coin_management);
Expand Down Expand Up @@ -517,7 +508,7 @@ fun test_deploy_interchain_token() {
.write_u256(token_id.to_u256())
.write_bytes(source_channel.to_address().to_bytes())
.write_bytes(destination_address)
.write_u256((amount as u256) * scaling)
.write_u256((amount as u256))
.write_bytes(b"");

assert!(
Expand Down Expand Up @@ -546,7 +537,6 @@ fun test_receive_interchain_transfer() {
string::utf8(b"Name"),
ascii::string(b"Symbol"),
10,
12,
);

let amount = 1234;
Expand Down Expand Up @@ -595,9 +585,7 @@ fun test_receive_interchain_transfer_with_data() {
string::utf8(b"Name"),
ascii::string(b"Symbol"),
10,
12,
);
let scaling = coin_info.scaling();

let amount = 1234;
let data = b"some_data";
Expand Down Expand Up @@ -646,7 +634,7 @@ fun test_receive_interchain_transfer_with_data() {
assert!(received_source_chain == source_chain);
assert!(received_source_address == its_source_address);
assert!(received_data == data);
assert!(received_coin.value() == amount / (scaling as u64));
assert!(received_coin.value() == amount);

clock.destroy_for_testing();
channel.destroy();
Expand All @@ -665,9 +653,7 @@ fun test_receive_deploy_interchain_token() {
let source_address = ascii::string(b"Address");
let name = b"Token Name";
let symbol = b"Symbol";
let remote_decimals = 12;
let decimals = if (remote_decimals > DECIMALS_CAP) DECIMALS_CAP
else remote_decimals;
let decimals = 9;
let token_id: u256 = 1234;

its.value_mut!(b"").create_unregistered_coin(symbol, decimals, ctx);
Expand All @@ -678,7 +664,7 @@ fun test_receive_deploy_interchain_token() {
.write_u256(token_id)
.write_bytes(name)
.write_bytes(symbol)
.write_u256((remote_decimals as u256))
.write_u256((decimals as u256))
.write_bytes(vector::empty());
let payload = writer.into_bytes();

Expand Down Expand Up @@ -720,7 +706,6 @@ fun test_mint_as_distributor() {
let mut its = create_for_testing(ctx);
let symbol = b"COIN";
let decimals = 9;
let remote_decimals = 18;

let (treasury_cap, coin_metadata) = its::coin::create_treasury_and_metadata(
symbol,
Expand All @@ -729,7 +714,6 @@ fun test_mint_as_distributor() {
);
let coin_info = its::coin_info::from_metadata<COIN>(
coin_metadata,
remote_decimals,
);
let mut coin_management = its::coin_management::new_with_cap(treasury_cap);

Expand Down Expand Up @@ -759,7 +743,6 @@ fun test_mint_to_as_distributor() {
let mut its = create_for_testing(ctx);
let symbol = b"COIN";
let decimals = 9;
let remote_decimals = 18;

let (treasury_cap, coin_metadata) = its::coin::create_treasury_and_metadata(
symbol,
Expand All @@ -768,7 +751,6 @@ fun test_mint_to_as_distributor() {
);
let coin_info = its::coin_info::from_metadata<COIN>(
coin_metadata,
remote_decimals,
);
let mut coin_management = its::coin_management::new_with_cap(treasury_cap);

Expand Down Expand Up @@ -796,7 +778,6 @@ fun test_burn_as_distributor() {
let mut its = create_for_testing(ctx);
let symbol = b"COIN";
let decimals = 9;
let remote_decimals = 18;
let amount = 1234;

let (
Expand All @@ -806,7 +787,6 @@ fun test_burn_as_distributor() {
let coin = treasury_cap.mint(amount, ctx);
let coin_info = its::coin_info::from_metadata<COIN>(
coin_metadata,
remote_decimals,
);
let mut coin_management = its::coin_management::new_with_cap(treasury_cap);

Expand Down
4 changes: 0 additions & 4 deletions move/its/sources/types/coin_data.move
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,3 @@ public(package) fun coin_management_mut<T>(
): &mut CoinManagement<T> {
&mut self.coin_management
}

public(package) fun coin_scaling<T>(self: &CoinData<T>): u256 {
self.coin_info.scaling()
}
Loading