Conversation
There was a problem hiding this comment.
A bit more information regarding deployment, testing and multisig:
Installation
https://docs.sui.io/getting-started/onboarding/sui-install#quick-install
$ curl -sSfL https://raw.githubusercontent.com/Mystenlabs/suiup/main/install.sh | sh
$ suiup install sui@testnet # or mainnet
$ suiup default set sui@testnet # or mainnetSome usefull initial commands:
$ sui client active-address
$ sui client faucet # or https://faucet.suilearn.io/
$ sui client balancePackage deployment
- First we need to publish package:
$ sui client publish- Then call
initialize:
sui client call --package <Package address> --module omni_bridge --function initialize --args <BridgeState> <NEAR MPC derived address (20 bytes)> 14Note
Both package address and bridge state could be found after executing first command (sui client publish)
The 14 is the ChainKind::Sui discriminant; a wrong value can be corrected later with set_chain_id (admin).
Calling methods
$ sui client ptb --split-coins gas "[1000000]" --assign pay --move-call 0x2::coin::zero "<0x2::sui::SUI>" --assign zero_fee --move-call <Package address>::omni_bridge::init_transfer "<0x2::sui::SUI>" @<BridgeState> pay.0 0 zero_fee '"near:frolik.testnet"' "vector[]"
# https://testnet.suivision.xyz/txblock/HcrYCissQ4qS1bF5DXa5zmejYiHVwupPWMuq1t9eYiot?tab=OverviewMultisig
https://docs.sui.io/develop/transactions/transaction-auth/multisig
| /// Sui coins are types, not addresses: for tokens this carries | ||
| /// `keccak256(canonical coin type string)`; for accounts, the native | ||
| /// 32-byte Sui address. | ||
| pub type SuiAddress = H256; |
There was a problem hiding this comment.
Sui treats coins differently as in Aptos, I decided to keep H256 for more similarity between move-related chains and store hash as an address, but maybe it's more transparent to use bounded string here
| signature: &vector<u8>, | ||
| expected_address: &vector<u8>, | ||
| ) { | ||
| assert!(signature.length() == 65, E_INVALID_SIGNATURE_LENGTH); |
There was a problem hiding this comment.
FYI, signature of this method is a bit different from Aptos, since we pass v as a last byte
There was a problem hiding this comment.
Pull request overview
Adds first-class Sui support to Omni Bridge by introducing a new Sui Move contract package (plus a per-token template package), extensive Move unit tests for payload/signature/bridge flows, NEAR-side type wiring for ChainKind::Sui / OmniAddress::Sui, and CI workflows to build/test and package artifacts.
Changes:
- Introduce
sui/Move package implementing bridge flows (init_transfer,fin_transfer,deploy_token, metadata logging/updates) and shared utilities (borsh encoders, signature verification, coin identity helpers). - Add comprehensive Sui Move unit tests validating borsh layouts, secp256k1 signature recovery, nonce bitmap replay protection, and deploy/mint/burn + lock/unlock scenarios.
- Wire Sui into NEAR-side enums/types/tests and extend CI to build/test Sui and include Sui/Aptos artifacts in contract update workflow.
Reviewed changes
Copilot reviewed 24 out of 26 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| sui/token_template/sources/template_coin.move | Per-token Move template used to publish bridged NEAR-originated coins on Sui. |
| sui/token_template/Move.toml | Move manifest for the token template package. |
| sui/token_template/Move.lock | Locked Sui framework dependencies for the token template package. |
| sui/token_template/.gitignore | Ignore build artifacts for the token template package. |
| sui/tests/utils_tests.move | Unit tests for signature verification, decimals clamping, and coin identity helpers. |
| sui/tests/test_coin.move | Test-only coin helper to create real TreasuryCap/CoinMetadata fixtures for deploy flows. |
| sui/tests/omni_bridge_tests.move | End-to-end unit tests for init/fin transfer, replay protection, deploy_token, metadata updates, roles/pause/version gating. |
| sui/tests/bridge_types_tests.move | Byte-exact tests for Sui-side borsh layouts of metadata/transfer payloads. |
| sui/tests/borsh_tests.move | Unit tests for borsh helper encoders (byte vec + string). |
| sui/sources/utils.move | Core utilities: secp256k1 “Ethereum-style” signature verification + type-id/token-id helpers. |
| sui/sources/omni_bridge.move | Main Sui bridge contract: shared state, roles, pause flags, transfers, deploy_token, events, and views. |
| sui/sources/bridge_types.move | Cross-chain payload structs and borsh serialization mirroring sibling chains. |
| sui/sources/borsh.move | Borsh sequence encoders (u32-LE length prefix) used by payload encoding. |
| sui/README.md | Sui-specific documentation: trust model, token identity, deploy flows, residual risks, and testing guide. |
| sui/Move.toml | Move manifest for the main OmniBridge Sui package. |
| sui/Move.lock | Locked Sui framework dependencies for the main Sui package. |
| sui/CLAUDE.md | Developer documentation for architecture, invariants, and module layout of the Sui contract. |
| sui/.gitignore | Ignore build artifacts and local Published.toml to keep signature tests stable. |
| near/omni-types/src/tests/lib_test.rs | Extend enum-stability and native-token tests to cover ChainKind::Sui / OmniAddress::Sui. |
| near/omni-types/src/lib.rs | Add ChainKind::Sui, OmniAddress::Sui(H256), and native SUI token-id constant wiring. |
| near/omni-tests/src/omni_token.rs | Include Sui factory address in omni-token integration test routing. |
| near/omni-tests/src/helpers.rs | Add helper returning a canonical test Sui factory OmniAddress. |
| near/omni-bridge/src/lib.rs | Teach origin-chain detection to recognize “sui” prefixes. |
| .github/workflows/update-contracts.yaml | Add Aptos/Sui CLI install + build steps and package Sui/Aptos artifacts for releases. |
| .github/workflows/sui.yaml | New CI workflow to install Sui CLI and run build/tests for sui/ + build token template. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let mut sig = *signature; | ||
| let v = &mut sig[64]; | ||
| if (*v >= 27) { | ||
| *v = *v - 27; | ||
| }; | ||
|
|
||
| let compressed = ecdsa_k1::secp256k1_ecrecover(&sig, message_bytes, 0); |
There was a problem hiding this comment.
Technically Aptos has the same "flaw":
omni-bridge/aptos/sources/utils.move
Lines 47 to 48 in f499d46
and starknet has the loosest check:
omni-bridge/starknet/src/omni_bridge.cairo
Lines 398 to 406 in f499d46
But I'm not sure how critical is that
cc @karim-en
|
@claude review |
Pull request overviewAdds the Sui side of the Omni Bridge: a Move package ( I cross-checked the payload encoding, signature scheme, and enum wiring against the Aptos sibling and the NEAR Changes:
Reviewed changesPer-file summary
FindingsVerified and correct:
Non-blocking (follow-ups / suggestions):
✅ Approved |
Adds the Sui side of the Omni Bridge: a Move package mirroring the
Aptos/Starknet contracts, plus the NEAR-side type wiring and CI.
What's inside
sui/Move package:init_transfer— send tokens Sui → NEAR: locks native coins in bridgecustody (or burns bridge-deployed ones), collects an optional SUI
native fee, and emits an
InitTransferevent for the NEAR MPC to read(no Wormhole).
fin_transfer— receive tokens NEAR → Sui: verifies the NEAR MPCsecp256k1 signature over the borsh payload, replay-protected by a
destination-nonce bitmap, then unlocks or mints to the recipient.
deploy_token/log_metadata— token registration in bothdirections. Sui can't create coins at runtime (one-time-witness rule),
so NEAR-originated tokens are published from
sui/token_template/andbound to the MPC-signed metadata payload (zero-supply TreasuryCap +
surrendered UpgradeCap + metadata equality checks).
version-gated shared state with
migratefor Sui's package-upgrademodel.
token id is
keccak256(canonical coin type string); payload layout isbyte-identical to Aptos. Chain id = 14 (
ChainKind::Sui), decimalsclamped to 9.
omni-types/omni-bridge:ChainKind::Sui,OmniAddress::Sui(H256), token prefix, native-token constant, tests.(Event parsers / mpc-prover dispatch are follow-ups, blocked on near/mpc
adding Sui read support.)
sui.yaml(build + test) and Aptos/Sui release artifacts inupdate-contracts.yaml.Testing
secp256k1 signature vectors (positive and negative), generated offline
against an independent encoder implementation.
log_metadata → init_transfer (lock) → signed fin_transfer (unlock) →
replay correctly rejected → template publish → deploy_token →
fin_transfer mint → init_transfer burn. Lock/unlock and mint/burn paths
both verified on-chain, and event
token_addressvalues matched theoffline keccak ids exactly.
key — not for production use):
https://testnet.suivision.xyz/txblock/HcrYCissQ4qS1bF5DXa5zmejYiHVwupPWMuq1t9eYiot
See
sui/README.mdfor the trust model, the documented deploy_tokenfront-running trade-off, and the deployment guide in
sui/deployment.md.