@unicitylabs/bridge-core 0.2.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +207 -0
- package/lib/index.js +30 -0
- package/package.json +44 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@unicitylabs/bridge-core` — the chain-neutral bridge contracts (08 Phase 4,
|
|
3
|
+
* the three-boundary abstraction). A wallet's bridge-in orchestration runs on
|
|
4
|
+
* these interfaces alone; each source chain (Tron today, EVM next) ships a plugin
|
|
5
|
+
* that *implements* them. The orchestrator therefore never imports a chain
|
|
6
|
+
* package — only this one — so adding a chain is additive, never a fork.
|
|
7
|
+
*
|
|
8
|
+
* The three boundaries:
|
|
9
|
+
* - {ChainWallet} connect · live account/network (no reads, no sends)
|
|
10
|
+
* - {ReceiptReader} node reads: tx receipts (no signing)
|
|
11
|
+
* - {BridgeSourceAdapter} "deposit X for recipient" -> opaque {DepositStep}[],
|
|
12
|
+
* decode the commit, build the Unicity mint request
|
|
13
|
+
* plus {BridgePresentation} (explorer link + address validation) for the UI.
|
|
14
|
+
*/
|
|
15
|
+
import type { IMintJustificationVerifier } from '@unicitylabs/state-transition-sdk/lib/transaction/verification/IMintJustificationVerifier.js';
|
|
16
|
+
/**
|
|
17
|
+
* The wallet capabilities the orchestrator needs: connect once, then read the
|
|
18
|
+
* **live** account/network before every signature. No signing here — the deposit
|
|
19
|
+
* steps sign via the wallet the adapter closed over.
|
|
20
|
+
*/
|
|
21
|
+
export interface ChainWallet {
|
|
22
|
+
connect(): Promise<string>;
|
|
23
|
+
getAddress(): Promise<string>;
|
|
24
|
+
getNetwork(): Promise<number>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A committing/approval tx receipt the orchestrator inspects only for revert; the
|
|
28
|
+
* rest is opaque and handed back to the adapter's `decodeCommit`. `null` until the
|
|
29
|
+
* tx is mined.
|
|
30
|
+
*/
|
|
31
|
+
export interface TxReceipt {
|
|
32
|
+
readonly success: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** Node-read surface the orchestrator needs: a tx receipt by id. */
|
|
35
|
+
export interface ReceiptReader {
|
|
36
|
+
getReceipt(txid: string): Promise<TxReceipt | null>;
|
|
37
|
+
}
|
|
38
|
+
/** One opaque step the orchestrator runs blindly (sign+broadcast → txid). */
|
|
39
|
+
export interface DepositStep {
|
|
40
|
+
/** Progress label shown while the step runs. */
|
|
41
|
+
readonly label: string;
|
|
42
|
+
/** Whether the orchestrator must wait for this tx to succeed before the next step. */
|
|
43
|
+
readonly awaitReceipt: boolean;
|
|
44
|
+
/** Sign + broadcast; resolves to the txid. The wallet + call are the adapter's concern. */
|
|
45
|
+
send(): Promise<string>;
|
|
46
|
+
}
|
|
47
|
+
/** Recovery material the orchestrator persists before the committing step. */
|
|
48
|
+
export interface DepositRecovery {
|
|
49
|
+
readonly tokenIdHex: string;
|
|
50
|
+
readonly saltHex: string;
|
|
51
|
+
readonly recipientCommitmentHex: string;
|
|
52
|
+
readonly coinIdHex: string;
|
|
53
|
+
readonly tokenTypeHex: string;
|
|
54
|
+
readonly chainId: number;
|
|
55
|
+
}
|
|
56
|
+
export interface PreparedDeposit {
|
|
57
|
+
readonly recovery: DepositRecovery;
|
|
58
|
+
/** Ordered steps; the one at {commitIndex} carries the commit (lock) event. */
|
|
59
|
+
readonly steps: readonly DepositStep[];
|
|
60
|
+
readonly commitIndex: number;
|
|
61
|
+
}
|
|
62
|
+
/** Decoded commit (lock) facts the mint justification binds to. */
|
|
63
|
+
export interface CommitInfo {
|
|
64
|
+
readonly nonce: bigint;
|
|
65
|
+
readonly blockNumber: bigint;
|
|
66
|
+
readonly logIndex: number;
|
|
67
|
+
}
|
|
68
|
+
/** A chain-neutral Unicity mint request (the orchestrator hands this to the wallet via {mintBridgedToken}). */
|
|
69
|
+
export interface MintRequest {
|
|
70
|
+
readonly coinIdHex: string;
|
|
71
|
+
readonly amount: bigint;
|
|
72
|
+
/** The genesis value payload, in the wallet's value format. */
|
|
73
|
+
readonly mintData: Uint8Array;
|
|
74
|
+
readonly tokenType: Uint8Array;
|
|
75
|
+
readonly salt: Uint8Array;
|
|
76
|
+
readonly genesisReason: Uint8Array;
|
|
77
|
+
readonly mintJustificationVerifiers: readonly IMintJustificationVerifier[];
|
|
78
|
+
}
|
|
79
|
+
export interface DepositParams {
|
|
80
|
+
readonly amount: bigint;
|
|
81
|
+
readonly networkId: number;
|
|
82
|
+
readonly recipientPubkey?: Uint8Array;
|
|
83
|
+
readonly ownerPredicateCbor?: Uint8Array;
|
|
84
|
+
readonly approveAmount?: bigint;
|
|
85
|
+
}
|
|
86
|
+
export interface MintRequestArgs {
|
|
87
|
+
readonly saltHex: string;
|
|
88
|
+
readonly amount: bigint;
|
|
89
|
+
readonly commit: CommitInfo;
|
|
90
|
+
readonly commitTxid: string;
|
|
91
|
+
}
|
|
92
|
+
/** The chain-neutral bridge-in source the orchestrator drives. */
|
|
93
|
+
export interface BridgeSourceAdapter {
|
|
94
|
+
/** Derive the recovery material + the ordered opaque deposit steps. */
|
|
95
|
+
prepareDeposit(params: DepositParams): Promise<PreparedDeposit>;
|
|
96
|
+
/** Decode a committing tx's raw receipt into {CommitInfo}; null if the event isn't present yet. */
|
|
97
|
+
decodeCommit(rawReceipt: unknown): CommitInfo | null;
|
|
98
|
+
/** Build the Unicity mint request for a (recovered) committed deposit. */
|
|
99
|
+
buildMintRequest(args: MintRequestArgs): MintRequest;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The chain-specific UI presentation a bridge needs: a source-chain explorer link
|
|
103
|
+
* and destination-address validation. The wallet UI holds one per bridge and never
|
|
104
|
+
* keys on a numeric chainId or hardcodes a chain's URL / address shape — the bridge
|
|
105
|
+
* supplies it.
|
|
106
|
+
*/
|
|
107
|
+
export interface BridgePresentation {
|
|
108
|
+
/** Block-explorer URL for a source-chain transaction. */
|
|
109
|
+
explorerTxUrl(txid: string): string;
|
|
110
|
+
/** Structural validity of a destination address on this bridge's source chain. */
|
|
111
|
+
validateAddress(addr: string): boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Chain-neutral fields every bridged-asset manifest carries, whatever the source
|
|
115
|
+
* chain family. Integrity-pinned; all byte fields are lowercase hex, no `0x`. The
|
|
116
|
+
* chain is identified by {chainRef} — a CAIP-2-style string/hex reference
|
|
117
|
+
* (`tron:0x…`, `eip155:1`) — not a JavaScript number; a family's native numeric id
|
|
118
|
+
* (if any) lives inside that family's plugin manifest variant.
|
|
119
|
+
*/
|
|
120
|
+
export type ChainFamily = 'tron' | 'eip155';
|
|
121
|
+
export interface BridgeManifestBase {
|
|
122
|
+
/** Human label for the bridged asset, e.g. "USDT (bridged · Tron)". */
|
|
123
|
+
readonly label: string;
|
|
124
|
+
readonly symbol: string;
|
|
125
|
+
/** CAIP-2-style chain reference (e.g. `tron:0xcd8690dc`) — the generic chain identity. */
|
|
126
|
+
readonly chainRef: string;
|
|
127
|
+
/** Deployed vault (lock) address, in any of the chain's address forms. */
|
|
128
|
+
readonly vault: string;
|
|
129
|
+
/** Bridged asset (token) address, same forms. */
|
|
130
|
+
readonly asset: string;
|
|
131
|
+
/** Source-finality threshold an independent receiver enforces (K). */
|
|
132
|
+
readonly confirmations: number;
|
|
133
|
+
/** Token decimals. */
|
|
134
|
+
readonly decimals: number;
|
|
135
|
+
/** Part-B return-service base URL (bridge-back handoff). */
|
|
136
|
+
readonly returnServiceUrl: string;
|
|
137
|
+
/** `BridgeBackReason` CBOR tag the vault/prover bind (frozen config). */
|
|
138
|
+
readonly reasonTag: number;
|
|
139
|
+
/** 32-byte lock domain separator the deployed vault was constructed with (hex). */
|
|
140
|
+
readonly lockDomain: string;
|
|
141
|
+
/** 32-byte nullifier domain separator (hex). */
|
|
142
|
+
readonly nullifierDomain: string;
|
|
143
|
+
/** Groth16 verification key fingerprint the vault enforces (`0x…`); display/ops. */
|
|
144
|
+
readonly vkey: string;
|
|
145
|
+
/** 32-byte `configHash` the deployed vault self-derives (hex). Cross-checked at load. */
|
|
146
|
+
readonly configHash: string;
|
|
147
|
+
/** Optional explicit `tokenTypeHex`; derived + cross-checked when present. */
|
|
148
|
+
readonly tokenTypeHex?: string;
|
|
149
|
+
/** Optional explicit `coinIdHex`; derived + cross-checked when present. */
|
|
150
|
+
readonly coinIdHex?: string;
|
|
151
|
+
readonly disabledReason?: string;
|
|
152
|
+
}
|
|
153
|
+
export interface WalletTokenPlugin {
|
|
154
|
+
readonly id: string;
|
|
155
|
+
readonly mintJustificationVerifiers: readonly IMintJustificationVerifier[];
|
|
156
|
+
}
|
|
157
|
+
export interface WalletMintResult {
|
|
158
|
+
readonly success: boolean;
|
|
159
|
+
readonly tokenId?: string;
|
|
160
|
+
readonly error?: string;
|
|
161
|
+
}
|
|
162
|
+
export interface WalletBurnResult {
|
|
163
|
+
readonly success: boolean;
|
|
164
|
+
readonly burnId: string;
|
|
165
|
+
readonly tokenId: string;
|
|
166
|
+
readonly burnedToken?: Uint8Array;
|
|
167
|
+
readonly error?: string;
|
|
168
|
+
}
|
|
169
|
+
export interface WalletPendingBurn {
|
|
170
|
+
readonly burnId: string;
|
|
171
|
+
readonly tokenId: string;
|
|
172
|
+
readonly reasonBytes: Uint8Array;
|
|
173
|
+
readonly burnedToken: Uint8Array | null;
|
|
174
|
+
readonly settled: boolean;
|
|
175
|
+
}
|
|
176
|
+
export interface BridgePayments {
|
|
177
|
+
mintCustom(request: {
|
|
178
|
+
readonly tokenType: Uint8Array;
|
|
179
|
+
readonly salt: Uint8Array;
|
|
180
|
+
readonly data: Uint8Array;
|
|
181
|
+
readonly justification?: Uint8Array;
|
|
182
|
+
readonly assets: readonly {
|
|
183
|
+
coinId: string;
|
|
184
|
+
amount: bigint;
|
|
185
|
+
}[];
|
|
186
|
+
readonly mintJustificationVerifiers?: readonly IMintJustificationVerifier[];
|
|
187
|
+
}): Promise<WalletMintResult>;
|
|
188
|
+
burn(request: {
|
|
189
|
+
readonly tokenId: string;
|
|
190
|
+
readonly reasonBytes: Uint8Array;
|
|
191
|
+
}): Promise<WalletBurnResult>;
|
|
192
|
+
tokenJustification(tokenId: string): Promise<Uint8Array | null>;
|
|
193
|
+
pendingBurns(): Promise<readonly WalletPendingBurn[]>;
|
|
194
|
+
acknowledgeBurn(burnId: string): Promise<void>;
|
|
195
|
+
}
|
|
196
|
+
export declare function mintBridgedToken(payments: BridgePayments, request: MintRequest): Promise<WalletMintResult>;
|
|
197
|
+
export interface BurnForReturnArgs {
|
|
198
|
+
readonly tokenId: string;
|
|
199
|
+
readonly reasonBytes: Uint8Array;
|
|
200
|
+
readonly persist: (burnedToken: Uint8Array, burnId: string) => Promise<void>;
|
|
201
|
+
}
|
|
202
|
+
export interface BurnForReturnResult {
|
|
203
|
+
readonly burnId: string;
|
|
204
|
+
readonly burnedToken: Uint8Array;
|
|
205
|
+
}
|
|
206
|
+
export declare function burnForReturn(payments: BridgePayments, args: BurnForReturnArgs): Promise<BurnForReturnResult>;
|
|
207
|
+
export declare function recoverPendingBurns(payments: BridgePayments, persist: BurnForReturnArgs['persist']): Promise<readonly BurnForReturnResult[]>;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function mintBridgedToken(payments, request) {
|
|
2
|
+
return payments.mintCustom({
|
|
3
|
+
tokenType: request.tokenType,
|
|
4
|
+
salt: request.salt,
|
|
5
|
+
data: request.mintData,
|
|
6
|
+
justification: request.genesisReason,
|
|
7
|
+
assets: [{ coinId: request.coinIdHex, amount: request.amount }],
|
|
8
|
+
mintJustificationVerifiers: request.mintJustificationVerifiers,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
export async function burnForReturn(payments, args) {
|
|
12
|
+
const result = await payments.burn({ tokenId: args.tokenId, reasonBytes: args.reasonBytes });
|
|
13
|
+
if (!result.success || !result.burnedToken) {
|
|
14
|
+
throw new Error(`burn failed for token ${args.tokenId}: ${result.error ?? 'no burned blob returned'}`);
|
|
15
|
+
}
|
|
16
|
+
await args.persist(result.burnedToken, result.burnId);
|
|
17
|
+
await payments.acknowledgeBurn(result.burnId);
|
|
18
|
+
return { burnId: result.burnId, burnedToken: result.burnedToken };
|
|
19
|
+
}
|
|
20
|
+
export async function recoverPendingBurns(payments, persist) {
|
|
21
|
+
const recovered = [];
|
|
22
|
+
for (const pending of await payments.pendingBurns()) {
|
|
23
|
+
if (!pending.settled || pending.burnedToken === null)
|
|
24
|
+
continue;
|
|
25
|
+
await persist(pending.burnedToken, pending.burnId);
|
|
26
|
+
await payments.acknowledgeBurn(pending.burnId);
|
|
27
|
+
recovered.push({ burnId: pending.burnId, burnedToken: pending.burnedToken });
|
|
28
|
+
}
|
|
29
|
+
return recovered;
|
|
30
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unicitylabs/bridge-core",
|
|
3
|
+
"version": "0.2.0-dev.1",
|
|
4
|
+
"description": "Chain-neutral bridge contracts: the source-adapter, wallet/client boundaries, and presentation interfaces a wallet's bridge orchestration runs on. Chain plugins (Tron, EVM, …) implement these; the orchestrator never imports a chain package.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"lib",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./lib/index.d.ts",
|
|
16
|
+
"default": "./lib/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./lib/*.js": {
|
|
19
|
+
"types": "./lib/*.d.ts",
|
|
20
|
+
"default": "./lib/*.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/unicitynetwork/unicity-bridge.git",
|
|
26
|
+
"directory": "packages/bridge-core"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc --project tsconfig.json",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"test": "tsx --test test/*.test.ts"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=22"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@unicitylabs/state-transition-sdk": "3.0.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^22.0.0",
|
|
41
|
+
"tsx": "^4.19.0",
|
|
42
|
+
"typescript": "^5.6.0"
|
|
43
|
+
}
|
|
44
|
+
}
|