Skip to main content

Chain Links (Public)

A chain link is a verified association between an Orbinum alias and a wallet address on a foreign blockchain. When you attach a chain link, the runtime verifies on-chain that you control the external wallet — you are not just claiming ownership.

Chain links are public: the address is written to chain storage and visible to anyone.

For private cross-chain wallet registration, see Private links.


Supported signature schemes

The runtime validates external wallet ownership using a configurable signature scheme per chain. Governance registers each chain via add_supported_chain.

SchemeUsed bySignature lengthVerification
Eip191Ethereum and EVM-compatible chains65 bytes (ECDSA + recovery bit)EIP-191 prefix + Keccak-256 of AccountId32
Ed25519Solana and other Ed25519 chains64 bytesRaw Ed25519 signature of AccountId32

Note: the Ed25519 variant is raw Ed25519, not the Substrate Ed25519 wrapper. They use the same curve but different message framing.

The message signed by the external wallet is always the SCALE-encoded AccountId32 of the Orbinum account. This proves the external wallet explicitly authorized the link to this specific Orbinum identity.

Support for additional schemes — such as Schnorr/BIP340 for Bitcoin Taproot or raw Secp256k1 for Cosmos — will be added via governance as new SignatureScheme variants are introduced in the runtime.

Why Substrate accounts are excluded

Chain links are exclusively for wallets from external, non-Substrate ecosystems. Adding a chain link to another Substrate parachain account is not supported and is rejected at the pallet level (SubstrateNativeSchemeNotAllowed).

The reason is fundamental: in the Substrate key model, an AccountId32 is a public key. If you control the keypair on Orbinum, you already control the same address on any other Substrate chain — there is nothing cryptographically meaningful to prove. Allowing such links would create a false sense of "cross-chain verification" on something that is simply key identity reuse. Any future SignatureScheme variant for a Substrate-native scheme must implement is_for_external_chain() → false, which causes add_supported_chain to reject it automatically.


Chain ID convention

The chain_id: u32 in the pallet is an internal Orbinum registry identifier assigned by governance — not an automatic standard. However, the following conventions are recommended to avoid conflicts:

EcosystemConventionExamples
EVM chainsEIP-155 chain IDEthereum = 1, Polygon = 137, BSC = 56, Arbitrum = 42161
Non-EVM chainsSLIP-0044 coin typeBitcoin = 0, Litecoin = 2, Solana = 501

Using EIP-155 IDs for EVM chains is strongly recommended since they are widely known and already used by tooling. For non-EVM chains such as Bitcoin or Litecoin, there is no universal standard — SLIP-0044 (the HD wallet derivation path standard) provides a reasonable canonical source.

Chain ID convention

The chain_id: u32 is split into two namespaces using bit 31 as a discriminant, so EIP-155 and SLIP-0044 IDs never collide:

Bit 31RangeStandardPurpose
00x00000000 – 0x7FFFFFFFEIP-155EVM-compatible chains
10x80000000 – 0xFFFFFFFFSLIP-0044Non-EVM chains (Bitcoin, Solana, etc.)

Common registered IDs:

ChainStandardchain_id
EthereumEIP-1551
BNB Smart ChainEIP-15556
PolygonEIP-155137
Arbitrum OneEIP-15542161
BitcoinSLIP-00440x80000000
LitecoinSLIP-00440x80000002
SolanaSLIP-00440x800001F5
CosmosSLIP-00440x80000076

Governance MUST follow this convention when registering new chains. The canonical constants are defined in types::chain in the pallet source.


pallet: AccountMapping (index 14)
call: add_chain_link (index 8)
args:
chain_id: u32 — the registered chain identifier
address: Vec<u8> — the raw address bytes on the external chain
signature: Vec<u8> — the signature from the external wallet
origin: Signed (alias owner)

Steps executed on-chain:

  1. Verifies the caller has an alias (NoAlias).
  2. Checks the chain is supported (UnsupportedChain).
  3. Checks no link for chain_id already exists (ChainLinkAlreadyExists).
  4. Verifies the signature from address over encode(AccountId32).
  5. Stores the ChainLink { chain_id, address } in the IdentityRecord.
  6. Stores the reverse index (chain_id, address) → AccountId32 in ReverseChainLinks.

On success, emits:

ChainLinkAdded { account, chain_id, address }

Limits

  • Maximum 16 chain links per alias (shared with private links).
  • Maximum address length: 128 bytes (covers Bitcoin bech32, Solana base58, EVM hex).

pallet: AccountMapping (index 14)
call: remove_chain_link (index 9)
args: chain_id: u32
origin: Signed (alias owner)

Removes the link for chain_id from the IdentityRecord and deletes the reverse index entry. No signature required for removal — owning the alias is sufficient.

Emits: ChainLinkRemoved { account, chain_id }.


Governance: managing supported chains

Supported chains are registered by root (governance). This ensures that signature verification logic exists for a chain before any user can add a link to it.

pallet: AccountMapping (index 14)
call: add_supported_chain (index 11)
args: chain_id: u32, scheme: SignatureScheme
origin: Root

call: remove_supported_chain (index 12)
args: chain_id: u32
origin: Root

Removing a supported chain does not retroactively invalidate existing links.


Proxy call dispatch via linked wallet

A verified chain link enables universal proxy signing: an external wallet can authorize and dispatch any Substrate call on behalf of the Orbinum account, without holding ORB for gas.

pallet: AccountMapping (index 14)
call: dispatch_as_linked_account (index 13)
args:
owner: AccountId32 — the Orbinum account that owns the link
chain_id: u32
address: Vec<u8> — the external wallet address
signature: Vec<u8> — signature over the SCALE-encoded inner call
call: RuntimeCall — the call to execute as `owner`
origin: Signed (any relayer)

Execution flow:

  1. The runtime looks up (chain_id, address) in ReverseChainLinks and verifies it belongs to owner.
  2. Verifies the external wallet's signature over encode(call).
  3. Dispatches call with origin = Signed(owner).
  4. The relayer pays the transaction fee; owner authorizes the action.

Emits: ProxyCallExecuted { owner, chain_id, address }.

info

This feature enables Solana wallets (via Phantom) or hardware Ethereum wallets to control an Orbinum identity without ever interacting with the chain directly.


Chain link (public)Private link
Address on-chainYes, visibleNo, only a Poseidon commitment
Signature requiredYes, at registrationNo, at registration — only at reveal
ReversibleYes, via remove_chain_linkYes, while not revealed
Promoted to publicN/AYes, via reveal_private_link
Dispatch supportdispatch_as_linked_accountdispatch_as_private_link (ZK proof)

See Private links for the confidential alternative.