Skip to content

feat: sui support - #307

Draft
frolvanya wants to merge 1 commit into
mainfrom
feat/sui
Draft

feat: sui support#307
frolvanya wants to merge 1 commit into
mainfrom
feat/sui

Conversation

@frolvanya

Copy link
Copy Markdown
Contributor

Adds Sui support to the SDK and CLI. Contract side: Near-One/omni-bridge#633.

What's inside

  • New sui-bridge-client crate built on the MystenLabs sui-rust-sdk
    crates over gRPC (Sui JSON-RPC is decommissioned): init_transfer,
    fin_transfer, log_metadata, deploy_token, views, and MPC event
    logs.
  • deploy_token is fully automated despite Sui's one-time-witness rule:
    the crate vendors precompiled token-template bytecode and patches the
    identifiers and constants per token (no Move compiler dependency),
    then publishes and calls deploy_token<T> back-to-back. Symbol, name,
    and description live in a single vector<vector<u8>> constant so the
    Move verifier's duplicate-constant check can never reject a token
    (e.g. symbol == name).
  • omni-connector wiring: build_sui_mpc_sign_payload (raw BCS event
    contents, no JSON canonicalization), Sui variants and dispatch arms
    for deploy/init/fin/bind/claim-fee, storage-deposit derivation.
  • CLI: sui-init-transfer, sui-fin-transfer, sui-log-metadata
    (takes the coin type — Sui token ids are keccak hashes and can't be
    reversed), config/env/defaults for all three networks.
  • Pins: omni-types -> 67b37e6c (feat/sui; re-pin after #633 merges),
    near-mpc-contract-interface -> 9295cf29 (adds the Sui foreign-tx
    types; verified drop-in for existing chains).

Testing

  • MPC sign payload reproduces near/mpc's snapshot hash byte-exactly.
  • Bytecode patcher: byte-lossless identity patch, fixtures validated
    with sui move disassemble, edge cases covered (symbol == name,
    empty symbol/name, long names).
  • Ignored network tests against the Sui testnet deployment: reads and
    BCS-decodes the real InitTransfer event, checks finality, runs view
    simulations, and publish-simulates patched token modules (the node's
    own verifier accepts them).
  • cargo test --workspace green (136 tests), fmt/clippy clean.

Notes

  • End-to-end NEAR-side finalization waits on the omni-bridge contract's
    Sui prover dispatch (follow-up noted in #633); payloads are ready.
  • Mainnet defaults are placeholders until a mainnet deployment exists;
    testnet defaults point at the #633 test deployment.

@frolvanya

Copy link
Copy Markdown
Contributor Author

@claude review

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown

Pull request overview

Adds Sui as a new bridge chain across the whole SDK + CLI, mirroring the Aptos MPC-proof pattern. The centerpiece is a new sui-bridge-client crate that talks to Sui over gRPC (sui-rpc), builds programmable transaction blocks, and — because Sui can't create a currency at runtime (one-time-witness rule) — vendors a precompiled token_template module and patches its identifiers/constants per token at the binary-format table level, then publishes + deploy_token<T> back-to-back. MPC proof construction feeds the raw BCS event contents into ForeignTxSignPayload::Sui, validated against near/mpc's snapshot hash.

Changes:

  • New sui-bridge-client crate: builder, gRPC rpc wrappers, bytecode patcher, init_transfer/fin_transfer/log_metadata/deploy_token/views, MPC event-log extraction, unit + ignored network tests.
  • omni-connector: sui_bridge_client field + builder, build_sui_mpc_sign_payload, Sui variants for DeployTokenArgs/InitTransferArgs/FinTransferArgs, dispatch/helper methods, storage-deposit derivation, and Sui arms in every exhaustive ChainKind/OmniAddress match.
  • bridge-cli: sui-init-transfer/sui-fin-transfer/sui-log-metadata subcommands, CliConfig fields + or()/env_config()/all three default_config arms, defaults.rs constants, builder wiring.
  • bridge-connector-common: From<SuiBridgeClientError> + SuiRpcError/SuiOtherError variants.
  • evm-bridge-client: Sui folded into the "not an EVM chain" error arms.
  • Dependency pins bumped: omni-types -> 67b37e6c (feat/sui branch), near-mpc-contract-interface -> 9295cf29; new sui-*/tonic workspace deps.

Reviewed changes

Per-file summary
File Description
Cargo.toml / Cargo.lock Adds sui-bridge-client member + sui-*/tonic deps; bumps omni-types and near-mpc-contract-interface revs
bridge-cli/src/defaults.rs Sui RPC/bridge/state-object constants for mainnet (zero placeholders)/testnet/devnet
bridge-cli/src/main.rs CliConfig Sui fields threaded through or(), env_config(), all 3 default_config arms
bridge-cli/src/omni_connector_command.rs Sui* subcommands, dry-run gating, ChainKind::Sui match arms, client build in omni_connector()
evm-bridge-client/src/evm_bridge_client.rs ChainKind::Sui/OmniAddress::Sui added to non-EVM error arms
sui-bridge-client/src/builder.rs Builder; Ed25519 key parse (hex seed or suiprivkey), address parsing
sui-bridge-client/src/bytecode.rs Move binary-format table patcher for per-token module/OTW/decimals/params
sui-bridge-client/src/rpc.rs Thin gRPC wrappers (get_transaction[_opt], get_object)
sui-bridge-client/src/sui_bridge_client.rs Core client: transfers, deploy, views, event-log + MPC finality, digest/token-id helpers
sui-bridge-client/src/error.rs Error enum
sui-bridge-client/token_template/, src/template/.mv, tests/fixtures/*.mv Move source + vendored/fixture bytecode
sui-bridge-client/tests/testnet.rs Ignored network tests against the #633 testnet deployment
bridge-connector-common/src/result.rs From<SuiBridgeClientError> + new error variants
omni-connector/src/omni_connector.rs Full connector wiring incl. build_sui_mpc_sign_payload + snapshot-hash test

Findings

Blocking (must fix before merge):

  • Cargo.toml:621omni-types is pinned to 67b37e6c…, a commit on the unmerged feat/sui branch (per the PR description: "re-pin after #633 merges"). A feature-branch commit is only reproducibly fetchable while the branch keeps it reachable; if #633 is rebased/squash-merged and the branch is deleted, cargo can no longer resolve this rev and every build breaks. Gate this merge on re-pinning omni-types (and confirming near-mpc-contract-interface 9295cf29) to commits that live on main. This is a merge-ordering gate, not a code defect.

Non-blocking (nits, follow-ups, suggestions):

  • sui-bridge-client/src/sui_bridge_client.rs (deploy_token, ~L2103–2141 in the diff) — the published coin currency is created with clamped_decimals = min(origin_decimals, 9), but the deploy_token<T> call passes the unclamped origin_decimals (decimals_arg = tx.pure(&origin_decimals)). This is presumably intentional (the on-chain utils::normalize_decimals recomputes the cap, and the contract needs origin decimals for cross-chain amount scaling), but since the deploy path isn't exercised end-to-end yet, please confirm the Sui contract does not assert decimals == CoinMetadata.decimals — that would revert for any token with >9 origin decimals.
  • sui-bridge-client/src/sui_bridge_client.rs (fin_transfer/deploy_token) — the 65-byte MPC signature is passed whole (signature.to_bytes().to_vec()), whereas the Aptos client splits it into rs(64)+v(1). Passing the full compact signature matches Sui's ecdsa_k1::secp256k1_ecrecover, so this looks right, but it's untested end-to-end — worth a byte-level check against the #633 contract's expected vector<u8> layout (and that the trailing recovery byte is the 0/1 form Sui expects, not 27/28).
  • sui-bridge-client/src/bytecode.rs / sui_bridge_client.rs — numerous x as usize / x as u64 casts (e.g. offset as usize/len as usize in parse_module, event_index as u64 in get_event_log, .len() as u64 in the uleb/serialize helpers). The advisory -D clippy::as_conversions step will flag these; prefer usize::try_from(..) / u64::from(..) to match the repo convention (non-gating, since both clippy steps are continue-on-error).
  • bridge-cli/src/defaults.rs:669SUI_*_MAINNET are all-zero placeholders, so --network mainnet builds a client that fails at call time. Already documented in the PR; just confirm this ships guarded rather than silently attempting zero-address calls.

Nice touches worth calling out: the MPC sign payload has a snapshot-hash test against near/mpc, the bytecode patcher covers the symbol == name / empty-metadata duplicate-constant edge cases with a toolchain-validated fixture, and every ChainKind/OmniAddress exhaustive match plus the full CLI config-precedence chain (or/env_config/all three default_config arms) is wired for Sui.

⚠️ Issues found

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant