Skip to content

Commit

Permalink
sui: add foreign contracts table directly to state object
Browse files Browse the repository at this point in the history
  • Loading branch information
gator-boi committed Jun 21, 2023
1 parent 16c2b4b commit a9eb3c1
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 145 deletions.
92 changes: 0 additions & 92 deletions sui/contracts/hello_token/sources/dynamic/foreign_contracts.move

This file was deleted.

52 changes: 52 additions & 0 deletions sui/contracts/hello_token/sources/foreign_contracts.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/// This module manages the registration process for foreign Token Bridge
/// Relayer contracts. `chain` to `ExternalAddress` mappings are stored
/// as dynamic fields on the `State` object.
module hello_token::foreign_contracts {
// Sui dependencies.
use sui::table::{Self, Table};

// Wormhole dependencies.
use wormhole::state::{chain_id};
use wormhole::external_address::{Self, ExternalAddress};

// Errors.
const E_INVALID_CHAIN: u64 = 0;
const E_INVALID_CONTRACT_ADDRESS: u64 = 1;

// Only state should be able to mutate the `foreign_contracts` dynamic field
// object.
friend hello_token::state;

/// Adds a new `chain` to `contract_address` mapping.
public(friend) fun add(
foreign_contracts: &mut Table<u16, ExternalAddress>,
chain: u16,
contract_address: ExternalAddress,
) {
assert!(chain != 0 && chain != chain_id(), E_INVALID_CHAIN);
assert!(
external_address::is_nonzero(&contract_address),
E_INVALID_CONTRACT_ADDRESS
);

table::add(foreign_contracts, chain, contract_address);
}

/// Updates an existing `chain` to `contract_address` mapping. Reverts
/// if the new `contract_address` is the zero address.
public(friend) fun update(
foreign_contracts: &mut Table<u16, ExternalAddress>,
chain: u16,
contract_address: ExternalAddress
) {
assert!(
external_address::is_nonzero(&contract_address),
E_INVALID_CONTRACT_ADDRESS
);

*table::borrow_mut(
foreign_contracts,
chain
) = contract_address;
}
}
18 changes: 11 additions & 7 deletions sui/contracts/hello_token/sources/state.move
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module hello_token::state {
// Sui dependencies.
use sui::object::{Self, UID};
use sui::tx_context::{TxContext};
use sui::table::{Self, Table};

// Wormhole dependencies.
use wormhole::emitter::{Self, EmitterCap};
Expand All @@ -22,6 +23,7 @@ module hello_token::state {
// Errors.
const E_INVALID_CHAIN: u64 = 0;
const E_INVALID_CONTRACT_ADDRESS: u64 = 1;
const E_CONTRACT_DOES_NOT_EXIST: u64 = 2;

/// Object that holds this contract's state. Foreign contracts are
/// stored as dynamic object fields of `State`.
Expand All @@ -33,6 +35,9 @@ module hello_token::state {

/// Stores relayer fee and precision.
relayer_fee: RelayerFee,

/// Foreign contract registry.
foreign_contracts: Table<u16, ExternalAddress>,
}

/// Creates new `State` object. The `emitter_cap` and `relayer_fee`
Expand All @@ -49,11 +54,9 @@ module hello_token::state {
id: object::new(ctx),
emitter_cap: emitter::new(wormhole_state, ctx),
relayer_fee: relayer_fee::new(relayer_fee, relayer_fee_precision),
foreign_contracts: table::new(ctx)
};

// Make new foreign contracts map.
foreign_contracts::new(&mut state.id, ctx);

// Done.
state
}
Expand All @@ -67,13 +70,13 @@ module hello_token::state {
) {
if (contract_registered(self, chain)) {
foreign_contracts::update(
&mut self.id,
&mut self.foreign_contracts,
chain,
contract_address
);
} else {
foreign_contracts::add(
&mut self.id,
&mut self.foreign_contracts,
chain,
contract_address,
);
Expand Down Expand Up @@ -104,11 +107,12 @@ module hello_token::state {
}

public fun contract_registered(self: &State, chain: u16): bool {
foreign_contracts::has(&self.id, chain)
table::contains(&self.foreign_contracts, chain)
}

public fun foreign_contract_address(self: &State, chain: u16): ExternalAddress {
*foreign_contracts::contract_address(&self.id, chain)
assert!(contract_registered(self, chain), E_CONTRACT_DOES_NOT_EXIST);
*table::borrow(&self.foreign_contracts, chain)
}

public fun fee_value(self: &State): u64 {
Expand Down
6 changes: 3 additions & 3 deletions sui/env/testing.env
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export TESTING_COIN_10_TREASURY_ID=0x150748f30672d3248e8e066a110aa4016ef7164ee34
export TESTING_COIN_8_TREASURY_ID=0xa60073e03641dbe2fc56b75bd4df5fa121643c0df1c4d8b636205baf534bf4d9

### Hello Token
export TESTING_HELLO_TOKEN_ID=0x3b17ab9de6f1f14ee30fc3150e66fb86dbde7cffcbe5e76c108b29633c372120
export TESTING_HELLO_TOKEN_OWNER_CAPABILITY_ID=0x4f2248b5ec13d906b4412a96c6251101a61325b3631ae5d03574b94f0dbd1398
export TESTING_HELLO_TOKEN_UPGRADE_CAP_ID=0xae91893a5e1c01be4b32a78454c8b4eab720dceb22aa41b1f4aa1fcd92d98cec
export TESTING_HELLO_TOKEN_ID=0xefcd8d7c6548c5d137278a640f3467628886ecf78dc9b5025875000af3895e88
export TESTING_HELLO_TOKEN_OWNER_CAPABILITY_ID=0xf73fdcda3b270f9a13fedad84d14a49a3da6c6bdae72a0f7627edcb87885bb64
export TESTING_HELLO_TOKEN_UPGRADE_CAP_ID=0xa72ab60caf8e4302a421e1dcd471ed678b85bdffc5d22b7e28198636fc72db4f

### Guardian
export TESTING_DEVNET_GUARDIAN=cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0
Expand Down
41 changes: 3 additions & 38 deletions sui/ts/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,13 @@ export async function getDynamicObjectFields(
return dynamicObjectFieldInfo;
}

export async function getTableFromDynamicObjectField(
export async function getForeignContractsTable(
provider: JsonRpcProvider,
parentId: string,
childName: any
objectId: string
) {
const dynamicObjectInfo = await getDynamicObjectFields(
provider,
parentId,
childName
);

// Fetch the table's keys
const keys = await provider
.getDynamicFields({parentId: dynamicObjectInfo!.fields.id.id})
.getDynamicFields({parentId: objectId})
.then((result) => result.data);

if (keys.length == 0) {
Expand Down Expand Up @@ -174,34 +167,6 @@ export async function getCoinWithHighestBalance(
return coins[index];
}

export async function getTableByName(
provider: JsonRpcProvider,
stateId: string,
fieldName: string
) {
// Fetch relayer state dynamic fields.
const dynamicField = await provider
.getDynamicFields({parentId: stateId})
.then((result) =>
result.data.filter((name) =>
Buffer.from(name.name.value).toString().includes(fieldName)
)
);

if (dynamicField.length === null) {
return Promise.reject("table not found");
}

// Fetch the `relayer_fee` dynamic field.
const relayerFees = await getTableFromDynamicObjectField(
provider,
stateId,
dynamicField[0].name!
);

return relayerFees;
}

export function tokenBridgeNormalizeAmount(
amount: number,
decimals: number
Expand Down
10 changes: 5 additions & 5 deletions sui/ts/tests/02_hello_token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ import {
getWormholeFee,
getCoinWithHighestBalance,
parseHelloTokenPayload,
getTableByName,
createHelloTokenPayload,
getBalanceChangeFromTransaction,
calculateRelayerFee,
getForeignContractsTable,
} from "../src";

describe("2: Hello Token", () => {
Expand Down Expand Up @@ -134,11 +134,11 @@ describe("2: Hello Token", () => {
});
expect(result.digest).is.not.null;

// Fetch the `foreign_contracts` table.
const registeredContracts = await getTableByName(
// Fetch the registered contracts table from state.
const state = await getObjectFields(provider, stateId);
const registeredContracts = await getForeignContractsTable(
provider,
stateId,
"foreign_contracts"
state!.foreign_contracts.fields.id.id
);
expect(registeredContracts).has.length(1);

Expand Down

0 comments on commit a9eb3c1

Please sign in to comment.