@solidus-network/bridge
v0.2.1
Published
Solidus bridge SDK: credential export ids, bridge message bytes, consent payloads, gate reads and the bridge API client.
Readme
@solidus-network/bridge
The TypeScript side of the Solidus credential bridge. It gives you the ids and message bytes the chain and the mirror contracts agree on, the consent payload a wallet signs, the gate read a dApp runs, and a typed client for the bridge API.
Published on npm as @solidus-network/bridge.
How you know it agrees with the chain
Every byte-level function here is checked against test-fixtures/bridge/*.json. Those files are
generated by the Rust crate that the validators run, and the Solidity contracts are checked against
the same files. Three implementations, one set of bytes, and none of them builds its own
expectation.
Install
npm install @solidus-network/bridgeviem is a peer dependency and is used for TYPES only. If your app already has viem you pay
nothing. If it does not, you are not forced to install it.
Export a credential to another chain
The wallet signs a consent payload. Your backend hands it to the Solidus verify backend, which is where this package stops.
import { exportConsentTypedData, holderFromEvmAddress } from '@solidus-network/bridge'
const typedData = exportConsentTypedData(
{
credentialId: 'urn:solidus:credential:00ff',
domain: 11155111, // Sepolia
holder: holderFromEvmAddress(account.address),
consentExpiry: BigInt(Math.floor(Date.now() / 1000) + 3600),
},
11155111, // the chain id the wallet is on
mirrorAddress,
)
const signature = await walletClient.signTypedData(typedData)
// POST it to the verify backend with the credential id. The chain does the rest.The wallet renders the credential id, the destination and the expiry, because this returns typed data rather than a digest. A consent screen the holder cannot read is not consent.
Check a gate before the user pays for a revert
import { checkGate, credentialTypeHash, gateReasonName, holderFromEvmAddress } from '@solidus-network/bridge'
const result = await checkGate({
client: publicClient,
mirror: mirrorAddress,
holder: holderFromEvmAddress(account.address),
credentialTypeHash: credentialTypeHash('KycL2'),
issuerDidHash,
maxAge: 86_400n,
})
if (!result.ok) {
// 'no_export' | 'not_active' | 'issuer_not_accredited' | 'expired' | 'stale'
show(`cannot deposit: ${gateReasonName(result.reason)}`)
}checkGate walks the same checks in the same order as the on-chain gate, so the reason it gives is
the reason the transaction would revert with.
stale means our transport has gone quiet for longer than maxAge, not that the credential is bad.
The gate closes on silence on purpose: a destination chain that stops hearing from Solidus cannot
learn about a revocation, so it stops trusting what it last heard.
You supply the client. This package ships no RPC URL of its own.
What is not here yet
Phase 1 is credential status only. Quotes, transfers and referral rebates arrive with the USDC and
SLDS routes in later phases; encodeUsdcHook is present because the byte layout is already fixed,
not because anything moves value yet. Nothing in this package holds a key or signs anything.
