chainlesschain 0.161.12 → 0.162.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/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-B1dwBvzW.js → AIOps-5A54O3wF.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DfR4oLvh.js → ActionButton-epuY2GkZ.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D3ZYGXjr.js → Analytics-CIdxw7T5.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-CsmOoh-7.js → AppLayout-xR6YUHsS.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-B4gwDm63.js → Audit-D95nRcdZ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-T42uSArV.js → Backup-Cmw7ZTJD.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CFi52nMs.js → BaseInput-DgCEAL_E.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-D7Vvok1V.js → Chat-DAQAzZsA.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Dwaflpww.js → Checkbox-GRxUANnE.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BIqx3G0b.js → Codegen--6KIDt1W.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DzIUYUNu.js → Col-3s6dxuMx.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DKePtzhk.js → Community-D60pkEBz.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CirVV9Wq.js → Compact-CQR4QsWP.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CrXOr0sy.js → Compliance-KySNEhMK.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BEBP6Tht.js → Cowork-Yrrf_Vuu.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-k7nNUuqh.js → Cron-DSuuSKIQ.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-CBnX0Dhq.js → Crosschain-Dub0G9i4.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B48FszWS.js → DID-CbpCGV51.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-Pb3qfFpp.js → Dashboard-D29e0y01.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-pUHy4CQ2.js → Dropdown-DZY7X5v2.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CT0Qs-kR.js → Federation-dmrLzzMB.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CbJJp5BR.js → FormItemContext-EopsCGez.js} +1 -1
- package/src/assets/web-panel/assets/{Git-B3mGNLQe.js → Git-D3mb4RhK.js} +1 -1
- package/src/assets/web-panel/assets/{Governance-BKf4733q.js → Governance-8v034-Nr.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DZjU541G.js → Inference-Ddl-HQwQ.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C8L-7Dd1.js → KnowledgeGraph-DrRruyud.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CwDwOiKv.js → Logs-Bsu6lYQe.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-C2YWWU0M.js → Marketplace-Iyf2Xc23.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-dIbkOypF.js → McpTools-ljVE1lIN.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-7eF8WzcY.js → Memory-Ca48TtDU.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-C74GHLbX.js → MobileBridge-DZ3Ar6da.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CSEDo5Fo.js → Mtc-CRjBnVAT.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-DiJXxOrB.js → MtcAudit-CEC2eKez.js} +1 -1
- package/src/assets/web-panel/assets/Multisig-BHoQvNeL.js +7 -0
- package/src/assets/web-panel/assets/Multisig-kwPDnXnl.css +1 -0
- package/src/assets/web-panel/assets/{NLProgramming-DjF-gIUw.js → NLProgramming-9e5hIFvL.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BUE5CvMO.js → Notes-BEhZRadw.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-Dfbrobje.js → NotificationSettings-CzPbT9UE.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-C6YvqjQB.js → Organization-CvFg4VAr.js} +1 -1
- package/src/assets/web-panel/assets/{Overflow-BvHNhdMR.js → Overflow-Cm7ISeJl.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BO0hQHFS.js → P2P-BWN-wdfH.js} +1 -1
- package/src/assets/web-panel/assets/{Permissions-CCPlrJeP.js → Permissions-C4vKkP_t.js} +1 -1
- package/src/assets/web-panel/assets/{Pipeline-DTCL3FjJ.js → Pipeline-DQCShDeT.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-08DYgOe_.js → Privacy-Nc7LlSr3.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B7j-Z8sa.js → ProjectInit-DDkqXAED.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-CFqLhV1w.js → ProjectSettings-ia6GQr6A.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-BPlpx2UN.js → Projects-CNqXa5XY.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BCBPbVbF.js → Providers-EwarbUb8.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-C8Job6zl.js → QuickAsk-BAHQBw0d.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DOV_Aje-.js → Recommend-Ccgu6elV.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DOgK_dIK.js → Reputation-ai0gRNpj.js} +1 -1
- package/src/assets/web-panel/assets/{Row-8jdU1xYg.js → Row-BWLfAhHC.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B289OgNZ.js → RssFeed-CnuRtiQH.js} +1 -1
- package/src/assets/web-panel/assets/{Search-cr0AndFE.js → Search-Da0CvI_2.js} +1 -1
- package/src/assets/web-panel/assets/{Security-w4diykaE.js → Security-DEFeOeUv.js} +1 -1
- package/src/assets/web-panel/assets/{Services-dTxAI5cG.js → Services-CsfvCqCH.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-B3FiUiRo.js → Skeleton-DlRaGj_n.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DgtBTAFC.js → Skills-fjlZrsYq.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-B4Y6bvbL.js → Sla-DNSDuEt2.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C8FEvArc.js → SpeechSettings-Bj0t-JCf.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CHvV5L0m.js → SyncSettings-uO7Gy-BB.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-B4Py5ORS.js → Tasks-BSjsO-m8.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-MeTyXM5u.js → Templates-B03SSuXn.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Doiz7wyQ.js → Tenant-CTCPIBzq.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DSEAdwWN.js → Terminal-CQZcdArx.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BBrtaEKt.js → Tokens-CsNJIdNl.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-nPvjho27.js → Trigger-kYPQmm6P.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BFwPyS_6.js → Trust-mt-MiBeI.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DFsHoY1J.js → UkeySign-DBi8jgXw.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-FkSKqHE9.js → VideoEditing-CINSMEf5.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-AXo-_4-w.js → Wallet-DCVMgW0U.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-DoScnQ-4.js → WebAuthn-C9OjbTBs.js} +1 -1
- package/src/assets/web-panel/assets/{WorkflowEditor-IEMfIax-.js → WorkflowEditor-LM1HJs-S.js} +1 -1
- package/src/assets/web-panel/assets/{chat-pc1ciH6T.js → chat-Dz68Ixdp.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CjkIkB0e.js → colors-qf63Eax9.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CQZnkP5p.js → compact-item-r4YWRFGQ.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-B1McGnV-.js → createContext-C8Lwrn-C.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-CbkA6peP.js → hasIn-DsPi2kPP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8r6OBuk.js → index-1xqIvVM5.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn7SHV2e.js → index-5nOMJaLt.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChCCGHwz.js → index-B0KxtBNy.js} +1 -1
- package/src/assets/web-panel/assets/index-B3blziag.js +1 -0
- package/src/assets/web-panel/assets/{index-CGke5qZp.js → index-B8gs4g1v.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHpwwlmv.js → index-BFV6aAoX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWq64zmv.js → index-BKEl9Ahm.js} +1 -1
- package/src/assets/web-panel/assets/{index-NRWBOo4F.js → index-BfdIkZnT.js} +1 -1
- package/src/assets/web-panel/assets/{index-fqI1KnP_.js → index-BjPHuhxG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHtiecyM.js → index-BtCSUUKm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjxVsyn_.js → index-BxNXO95B.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGb36exe.js → index-Bz1O2KhE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcSe5y5O.js → index-BzzFMBIM.js} +1 -1
- package/src/assets/web-panel/assets/{index-uWvLy_3T.js → index-C2OFaKmx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTyhXFDW.js → index-C3VVwJcn.js} +1 -1
- package/src/assets/web-panel/assets/{index-C052wi94.js → index-C8SY0_S8.js} +1 -1
- package/src/assets/web-panel/assets/{index-wwQ_ZkWN.js → index-CCCX2ZSH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPzT5L14.js → index-CEbbycgJ.js} +3 -3
- package/src/assets/web-panel/assets/{index-CzZ3LxPK.js → index-CINVudo7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKwkP66s.js → index-CKRXnUTD.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4rhVRSV.js → index-CSCb-EY9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMjPzhsp.js → index-CY5X4uXO.js} +1 -1
- package/src/assets/web-panel/assets/{index-5c4JzwY3.js → index-CqmyLTa_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEENN81t.js → index-Cw48kkkH.js} +1 -1
- package/src/assets/web-panel/assets/{index-C0Lj7Yl0.js → index-D0mFFS7Y.js} +1 -1
- package/src/assets/web-panel/assets/index-D1XYuPHf.js +1 -0
- package/src/assets/web-panel/assets/{index-CKledOCh.js → index-D2BR3WQ-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsChgzu2.js → index-D4XgKgOF.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5mpCgak.js → index-DBpVVgRI.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bs-romIz.js → index-DGXVjiyF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNLeseG1.js → index-DQSweK5-.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJr12ypE.js → index-DXBc_lyR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFCQl1hk.js → index-DycrmZ_r.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di5tuS0d.js → index-I55BAmVG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJbqE5Sw.js → index-LQYz2tRO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYAWIXFt.js → index-cTFVNgoS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dzfj71tf.js → index-qLyVEtRM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJWYN-AT.js → index-qcVx0s-M.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjM0jsm1.js → index-wVpfPJXE.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BTloFqyf.js → initDefaultProps-CAgx2aHm.js} +1 -1
- package/src/assets/web-panel/assets/{motion-44iMBc1o.js → motion-DFuREFOd.js} +1 -1
- package/src/assets/web-panel/assets/{move-CyWQI5eW.js → move-DfcQIXuy.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CXfJtuFy.js → omit-BFZV2hmZ.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-ANFpSZes.js → pickAttrs-D98WQSur.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CigX-url.js → placementArrow-BlP2AN9q.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Ch48RA0m.js → responsiveObserve-DuI2xGQd.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BEz3LORF.js → slide-DSvqah_S.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-D9EniG8V.js → statusUtils-B-96ZLWF.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-C1IvuY3L.js → styleChecker-Br0YrCOO.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C92oHeXB.js → useFlexGapSupport-BD4Xr9XU.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CJhvFpgB.js → useFs-Ch5L3BnA.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BPkyunN_.js → vnode-BQi3uWRC.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B6Ipb64r.js → zoom-DaW-jbu7.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/crosschain.js +403 -1
- package/src/commands/pair.js +291 -0
- package/src/index.js +2 -0
- package/src/lib/cross-chain-mtc.js +275 -6
- package/src/lib/cross-chain.js +48 -2
- package/src/lib/lan-pairing-preflight.js +425 -0
- package/src/lib/lan-pairing-tokens.js +264 -0
- package/src/assets/web-panel/assets/Multisig-D-IuEDLa.css +0 -1
- package/src/assets/web-panel/assets/Multisig-FZTU5ri6.js +0 -1
- package/src/assets/web-panel/assets/index-BXfePRef.js +0 -1
- package/src/assets/web-panel/assets/index-Dc4fj_Ys.js +0 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `cc crosschain` — CLI surface for Phase 89 Cross-Chain Interoperability.
|
|
3
|
+
*
|
|
4
|
+
* #21 B.5 Layer 1 PR1 (2026-05-15): `cc crosschain bridge --require-multisig`
|
|
5
|
+
* opt-in routes outbound bridge through m-of-n multisig (domain
|
|
6
|
+
* `crosschain.bridge.outbound`); `cc crosschain bridge-consume <proposalId>`
|
|
7
|
+
* finalizes after threshold is reached. Mirrors marketplace purchase/consume.
|
|
3
8
|
*/
|
|
4
9
|
|
|
5
10
|
import fs from "node:fs";
|
|
@@ -8,6 +13,14 @@ import { Command } from "commander";
|
|
|
8
13
|
|
|
9
14
|
import { bootstrap } from "../runtime/bootstrap.js";
|
|
10
15
|
import { getHomeDir } from "../lib/paths.js";
|
|
16
|
+
import {
|
|
17
|
+
openMultisigManager,
|
|
18
|
+
defaultMultisigDbPath,
|
|
19
|
+
defaultMultisigLogPath,
|
|
20
|
+
readSecretKey,
|
|
21
|
+
} from "../lib/multisig-runtime.js";
|
|
22
|
+
|
|
23
|
+
const MULTISIG_BRIDGE_OUTBOUND_DOMAIN = "crosschain.bridge.outbound";
|
|
11
24
|
import {
|
|
12
25
|
getCrossChainMtcDir,
|
|
13
26
|
getBridgeMtcStatus,
|
|
@@ -111,6 +124,299 @@ function _maybeStageMtc(opts, opBuilder) {
|
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
126
|
|
|
127
|
+
/**
|
|
128
|
+
* #21 B.5 Layer 1 — open a multisig proposal for an outbound bridge.
|
|
129
|
+
* Does NOT insert into cc_bridges yet; bridge-consume does that after
|
|
130
|
+
* the proposal reaches threshold. Mirrors marketplace.purchase.
|
|
131
|
+
*/
|
|
132
|
+
async function _bridgePropose({
|
|
133
|
+
fromChain,
|
|
134
|
+
toChain,
|
|
135
|
+
amount,
|
|
136
|
+
asset,
|
|
137
|
+
sender,
|
|
138
|
+
recipient,
|
|
139
|
+
initiator,
|
|
140
|
+
alg,
|
|
141
|
+
key,
|
|
142
|
+
multisigDb,
|
|
143
|
+
multisigLog,
|
|
144
|
+
json,
|
|
145
|
+
}) {
|
|
146
|
+
if (!initiator) {
|
|
147
|
+
const out = {
|
|
148
|
+
status: "blocked",
|
|
149
|
+
reason: "missing_initiator",
|
|
150
|
+
path: "multisig",
|
|
151
|
+
};
|
|
152
|
+
if (json) console.log(JSON.stringify(out, null, 2));
|
|
153
|
+
else
|
|
154
|
+
console.error(
|
|
155
|
+
"✗ --initiator <did> required when --require-multisig is set",
|
|
156
|
+
);
|
|
157
|
+
process.exitCode = 2;
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
if (!key) {
|
|
161
|
+
const out = {
|
|
162
|
+
status: "blocked",
|
|
163
|
+
reason: "missing_key",
|
|
164
|
+
path: "multisig",
|
|
165
|
+
};
|
|
166
|
+
if (json) console.log(JSON.stringify(out, null, 2));
|
|
167
|
+
else
|
|
168
|
+
console.error(
|
|
169
|
+
"✗ --key <hex|path> required when --require-multisig is set",
|
|
170
|
+
);
|
|
171
|
+
process.exitCode = 2;
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const { store, mgr, close } = await openMultisigManager(
|
|
176
|
+
multisigDb,
|
|
177
|
+
multisigLog,
|
|
178
|
+
);
|
|
179
|
+
try {
|
|
180
|
+
const policy = store.getPolicy(MULTISIG_BRIDGE_OUTBOUND_DOMAIN);
|
|
181
|
+
if (!policy) {
|
|
182
|
+
const out = {
|
|
183
|
+
status: "blocked",
|
|
184
|
+
reason: "no_policy",
|
|
185
|
+
path: "multisig",
|
|
186
|
+
domain: MULTISIG_BRIDGE_OUTBOUND_DOMAIN,
|
|
187
|
+
};
|
|
188
|
+
if (json) console.log(JSON.stringify(out, null, 2));
|
|
189
|
+
else
|
|
190
|
+
console.error(
|
|
191
|
+
`✗ No multisig policy for domain "${MULTISIG_BRIDGE_OUTBOUND_DOMAIN}". Run: cc multisig policy set ${MULTISIG_BRIDGE_OUTBOUND_DOMAIN} --m <M> --members <json>`,
|
|
192
|
+
);
|
|
193
|
+
process.exitCode = 2;
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const secretKey = readSecretKey(key);
|
|
198
|
+
const payload = {
|
|
199
|
+
fromChain,
|
|
200
|
+
toChain,
|
|
201
|
+
asset: asset || "native",
|
|
202
|
+
amount,
|
|
203
|
+
sender: sender || null,
|
|
204
|
+
recipient: recipient || null,
|
|
205
|
+
};
|
|
206
|
+
const result = mgr.propose({
|
|
207
|
+
domain: MULTISIG_BRIDGE_OUTBOUND_DOMAIN,
|
|
208
|
+
payload,
|
|
209
|
+
policy,
|
|
210
|
+
initiator: { did: initiator, alg: alg || "Ed25519", secretKey },
|
|
211
|
+
});
|
|
212
|
+
const out = {
|
|
213
|
+
status: "needs_co_sign",
|
|
214
|
+
path: "multisig",
|
|
215
|
+
proposalId: result.proposal.id,
|
|
216
|
+
reachedThreshold: result.reachedThreshold,
|
|
217
|
+
requiredSigs: policy.m,
|
|
218
|
+
memberCount: policy.members.length,
|
|
219
|
+
payload,
|
|
220
|
+
};
|
|
221
|
+
if (json) {
|
|
222
|
+
console.log(JSON.stringify(out, null, 2));
|
|
223
|
+
} else {
|
|
224
|
+
console.log(
|
|
225
|
+
`↪ Routed through multisig (domain ${MULTISIG_BRIDGE_OUTBOUND_DOMAIN})`,
|
|
226
|
+
);
|
|
227
|
+
console.log(` proposalId: ${result.proposal.id}`);
|
|
228
|
+
console.log(` needs ${policy.m} of ${policy.members.length} signatures`);
|
|
229
|
+
if (result.reachedThreshold)
|
|
230
|
+
console.log(
|
|
231
|
+
` ✓ threshold reached on first signature — run: cc crosschain bridge-consume ${result.proposal.id}`,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return out;
|
|
235
|
+
} finally {
|
|
236
|
+
close();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* #21 B.5 Layer 1 — finalize an outbound bridge after multisig threshold.
|
|
242
|
+
* Reads the proposal's payload, executes the actual bridgeAsset() insert,
|
|
243
|
+
* then marks the proposal consumed. Mirrors marketplace.consume.
|
|
244
|
+
*
|
|
245
|
+
* PR4 — when `mtc=true`, additionally stage the bridge op with multisig
|
|
246
|
+
* provenance via `_maybeStageMtc` so closeBatch carries it into the MTC
|
|
247
|
+
* envelope leaf (and downstream wrapper attachment / Layer 3 broadcast).
|
|
248
|
+
*/
|
|
249
|
+
async function _bridgeConsume({
|
|
250
|
+
db,
|
|
251
|
+
proposalId,
|
|
252
|
+
multisigDb,
|
|
253
|
+
multisigLog,
|
|
254
|
+
json,
|
|
255
|
+
mtc,
|
|
256
|
+
mtcConfigDir,
|
|
257
|
+
}) {
|
|
258
|
+
const { mgr, close } = await openMultisigManager(multisigDb, multisigLog);
|
|
259
|
+
try {
|
|
260
|
+
const got = mgr.get(proposalId);
|
|
261
|
+
if (!got) {
|
|
262
|
+
const out = { status: "error", reason: "proposal_not_found" };
|
|
263
|
+
if (json) console.log(JSON.stringify(out, null, 2));
|
|
264
|
+
else console.error(`✗ No proposal: ${proposalId}`);
|
|
265
|
+
process.exitCode = 2;
|
|
266
|
+
return out;
|
|
267
|
+
}
|
|
268
|
+
if (got.proposal.domain !== MULTISIG_BRIDGE_OUTBOUND_DOMAIN) {
|
|
269
|
+
const out = {
|
|
270
|
+
status: "error",
|
|
271
|
+
reason: "wrong_domain",
|
|
272
|
+
expected: MULTISIG_BRIDGE_OUTBOUND_DOMAIN,
|
|
273
|
+
actual: got.proposal.domain,
|
|
274
|
+
};
|
|
275
|
+
if (json) console.log(JSON.stringify(out, null, 2));
|
|
276
|
+
else
|
|
277
|
+
console.error(
|
|
278
|
+
`✗ Proposal domain "${got.proposal.domain}" is not "${MULTISIG_BRIDGE_OUTBOUND_DOMAIN}" — use the matching consume command for that domain instead.`,
|
|
279
|
+
);
|
|
280
|
+
process.exitCode = 2;
|
|
281
|
+
return out;
|
|
282
|
+
}
|
|
283
|
+
if (got.proposal.state !== "reached") {
|
|
284
|
+
const out = {
|
|
285
|
+
status: "error",
|
|
286
|
+
reason: `proposal_state_${got.proposal.state}`,
|
|
287
|
+
};
|
|
288
|
+
if (json) console.log(JSON.stringify(out, null, 2));
|
|
289
|
+
else
|
|
290
|
+
console.error(
|
|
291
|
+
`✗ Proposal state is "${got.proposal.state}", need "reached" — sign more before consume.`,
|
|
292
|
+
);
|
|
293
|
+
process.exitCode = 2;
|
|
294
|
+
return out;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const payload = JSON.parse(got.proposal.payloadJcs);
|
|
298
|
+
|
|
299
|
+
// #21 B.5 Layer 2 PR1 — extract m-of-n provenance from the reached
|
|
300
|
+
// proposal and persist it alongside the bridge row. signatures are
|
|
301
|
+
// returned sorted by signer_did ASC (store.getSignatures), so the array
|
|
302
|
+
// ordering is canonical for any downstream onchain verifier.
|
|
303
|
+
const signatures = got.signatures || [];
|
|
304
|
+
// PR4 adds thresholdM + memberCountN so the carry-forward MTC staging
|
|
305
|
+
// can build the canonical multisig_provenance shape required by
|
|
306
|
+
// attachMultisigProvenance / verifyMultisigProvenance.
|
|
307
|
+
const multisigContext = {
|
|
308
|
+
proposalId: got.proposal.id,
|
|
309
|
+
thresholdM: got.proposal.thresholdM,
|
|
310
|
+
memberCountN: Array.isArray(got.proposal.memberSet)
|
|
311
|
+
? got.proposal.memberSet.length
|
|
312
|
+
: signatures.length,
|
|
313
|
+
signers: signatures.map((s) => s.signerDid),
|
|
314
|
+
partialSigs: signatures.map((s) => ({
|
|
315
|
+
did: s.signerDid,
|
|
316
|
+
alg: s.alg,
|
|
317
|
+
sig: Buffer.isBuffer(s.sig) ? s.sig.toString("hex") : String(s.sig),
|
|
318
|
+
})),
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const bridgeResult = bridgeAsset(
|
|
322
|
+
db,
|
|
323
|
+
{
|
|
324
|
+
fromChain: payload.fromChain,
|
|
325
|
+
toChain: payload.toChain,
|
|
326
|
+
asset: payload.asset,
|
|
327
|
+
amount: payload.amount,
|
|
328
|
+
senderAddress: payload.sender,
|
|
329
|
+
recipientAddress: payload.recipient,
|
|
330
|
+
},
|
|
331
|
+
multisigContext,
|
|
332
|
+
);
|
|
333
|
+
if (!bridgeResult.bridgeId) {
|
|
334
|
+
const out = {
|
|
335
|
+
status: "error",
|
|
336
|
+
reason: `bridge_insert_failed_${bridgeResult.reason}`,
|
|
337
|
+
proposalId,
|
|
338
|
+
};
|
|
339
|
+
if (json) console.log(JSON.stringify(out, null, 2));
|
|
340
|
+
else
|
|
341
|
+
console.error(
|
|
342
|
+
`✗ Bridge insert failed: ${bridgeResult.reason} — proposal left in "reached" state`,
|
|
343
|
+
);
|
|
344
|
+
process.exitCode = 1;
|
|
345
|
+
return out;
|
|
346
|
+
}
|
|
347
|
+
const finalizeRes = mgr.finalize(proposalId);
|
|
348
|
+
if (!finalizeRes.ok) {
|
|
349
|
+
const out = {
|
|
350
|
+
status: "error",
|
|
351
|
+
reason: finalizeRes.reason,
|
|
352
|
+
proposalId,
|
|
353
|
+
bridgeId: bridgeResult.bridgeId,
|
|
354
|
+
};
|
|
355
|
+
if (json) console.log(JSON.stringify(out, null, 2));
|
|
356
|
+
else
|
|
357
|
+
console.error(
|
|
358
|
+
`✗ Finalize failed: ${finalizeRes.reason} (bridge row ${bridgeResult.bridgeId} already inserted)`,
|
|
359
|
+
);
|
|
360
|
+
process.exitCode = 1;
|
|
361
|
+
return out;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// PR4 — opt-in MTC staging carries the multisig provenance forward into
|
|
365
|
+
// closeBatch / wrapper envelope. Same `_maybeStageMtc` helper as the
|
|
366
|
+
// legacy direct-bridge path, just with an enriched op shape including
|
|
367
|
+
// the canonical `multisig_provenance` field.
|
|
368
|
+
const mtcStaged = _maybeStageMtc({ mtc, mtcConfigDir }, () => ({
|
|
369
|
+
bridge_op: "lock",
|
|
370
|
+
src_chain: payload.fromChain,
|
|
371
|
+
dst_chain: payload.toChain,
|
|
372
|
+
src_tx_hash: bridgeResult.bridgeId,
|
|
373
|
+
amount: String(payload.amount),
|
|
374
|
+
asset: payload.asset || "native",
|
|
375
|
+
src_did: payload.sender || null,
|
|
376
|
+
dst_did: payload.recipient || null,
|
|
377
|
+
issued_at: new Date().toISOString(),
|
|
378
|
+
multisig_provenance: {
|
|
379
|
+
proposal_id: multisigContext.proposalId,
|
|
380
|
+
threshold_m: multisigContext.thresholdM,
|
|
381
|
+
member_count_n: multisigContext.memberCountN,
|
|
382
|
+
signers: multisigContext.signers,
|
|
383
|
+
partial_sigs: multisigContext.partialSigs,
|
|
384
|
+
},
|
|
385
|
+
}));
|
|
386
|
+
|
|
387
|
+
const out = {
|
|
388
|
+
status: "consumed",
|
|
389
|
+
proposalId,
|
|
390
|
+
bridgeId: bridgeResult.bridgeId,
|
|
391
|
+
fee: bridgeResult.fee,
|
|
392
|
+
payload,
|
|
393
|
+
// Layer 2 provenance — surface what was persisted on the bridge row.
|
|
394
|
+
signers: multisigContext.signers,
|
|
395
|
+
partialSigCount: multisigContext.partialSigs.length,
|
|
396
|
+
// PR4 — surface MTC staging result when --mtc was passed.
|
|
397
|
+
mtc: mtcStaged,
|
|
398
|
+
};
|
|
399
|
+
if (json) {
|
|
400
|
+
console.log(JSON.stringify(out, null, 2));
|
|
401
|
+
} else {
|
|
402
|
+
console.log(
|
|
403
|
+
`✓ Bridge consumed — ${payload.fromChain} → ${payload.toChain}, amount ${payload.amount} ${payload.asset}`,
|
|
404
|
+
);
|
|
405
|
+
console.log(
|
|
406
|
+
` bridgeId: ${bridgeResult.bridgeId} (fee ${bridgeResult.fee})`,
|
|
407
|
+
);
|
|
408
|
+
console.log(` proposalId: ${proposalId}`);
|
|
409
|
+
if (mtcStaged?.staged)
|
|
410
|
+
console.log(` MTC envelope staged: ${mtcStaged.path}`);
|
|
411
|
+
else if (mtcStaged && !mtcStaged.staged)
|
|
412
|
+
console.log(` MTC stage skipped: ${mtcStaged.reason}`);
|
|
413
|
+
}
|
|
414
|
+
return out;
|
|
415
|
+
} finally {
|
|
416
|
+
close();
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
114
420
|
export function registerCrossChainCommand(program) {
|
|
115
421
|
const cc = new Command("crosschain")
|
|
116
422
|
.description("Cross-chain interoperability (Phase 89)")
|
|
@@ -174,9 +480,49 @@ export function registerCrossChainCommand(program) {
|
|
|
174
480
|
"On success, stage an MTC bridge envelope (requires cc crosschain mtc-batch to close)",
|
|
175
481
|
)
|
|
176
482
|
.option("--mtc-config-dir <dir>", "Override MTC config root")
|
|
483
|
+
.option(
|
|
484
|
+
"--require-multisig",
|
|
485
|
+
"Route through m-of-n multisig (domain crosschain.bridge.outbound). Requires --initiator + --key + policy set.",
|
|
486
|
+
)
|
|
487
|
+
.option(
|
|
488
|
+
"--initiator <did>",
|
|
489
|
+
"Initiator DID for multisig proposal (required when --require-multisig)",
|
|
490
|
+
)
|
|
491
|
+
.option("--alg <alg>", "Initiator signing alg", "Ed25519")
|
|
492
|
+
.option(
|
|
493
|
+
"--key <hex|path>",
|
|
494
|
+
"Initiator secret key hex or path to hex file (required when --require-multisig)",
|
|
495
|
+
)
|
|
496
|
+
.option(
|
|
497
|
+
"--multisig-db <path>",
|
|
498
|
+
"Multisig SQLite DB path (default ~/.chainlesschain/multisig.db)",
|
|
499
|
+
)
|
|
500
|
+
.option(
|
|
501
|
+
"--multisig-log <path>",
|
|
502
|
+
"Multisig governance log path (default ~/.chainlesschain/multisig.governance.log)",
|
|
503
|
+
)
|
|
177
504
|
.option("--json", "JSON output")
|
|
178
|
-
.action((fromChain, toChain, amount, opts) => {
|
|
505
|
+
.action(async (fromChain, toChain, amount, opts) => {
|
|
179
506
|
const db = _dbFromCtx(cc);
|
|
507
|
+
|
|
508
|
+
if (opts.requireMultisig) {
|
|
509
|
+
return _bridgePropose({
|
|
510
|
+
db,
|
|
511
|
+
fromChain,
|
|
512
|
+
toChain,
|
|
513
|
+
amount: parseFloat(amount),
|
|
514
|
+
asset: opts.asset,
|
|
515
|
+
sender: opts.sender,
|
|
516
|
+
recipient: opts.recipient,
|
|
517
|
+
initiator: opts.initiator,
|
|
518
|
+
alg: opts.alg,
|
|
519
|
+
key: opts.key,
|
|
520
|
+
multisigDb: opts.multisigDb || defaultMultisigDbPath(),
|
|
521
|
+
multisigLog: opts.multisigLog || defaultMultisigLogPath(),
|
|
522
|
+
json: opts.json,
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
|
|
180
526
|
const result = bridgeAsset(db, {
|
|
181
527
|
fromChain,
|
|
182
528
|
toChain,
|
|
@@ -208,6 +554,37 @@ export function registerCrossChainCommand(program) {
|
|
|
208
554
|
console.log(`MTC stage skipped: ${mtc.reason}`);
|
|
209
555
|
});
|
|
210
556
|
|
|
557
|
+
cc.command("bridge-consume <proposalId>")
|
|
558
|
+
.description(
|
|
559
|
+
"Finalize a multisig-gated bridge after threshold reached — performs the SQLite insert and marks proposal consumed",
|
|
560
|
+
)
|
|
561
|
+
.option(
|
|
562
|
+
"--multisig-db <path>",
|
|
563
|
+
"Multisig SQLite DB path (default ~/.chainlesschain/multisig.db)",
|
|
564
|
+
)
|
|
565
|
+
.option(
|
|
566
|
+
"--multisig-log <path>",
|
|
567
|
+
"Multisig governance log path (default ~/.chainlesschain/multisig.governance.log)",
|
|
568
|
+
)
|
|
569
|
+
.option(
|
|
570
|
+
"--mtc",
|
|
571
|
+
"On success, stage an MTC bridge envelope carrying the multisig provenance (requires cc crosschain mtc-batch to close)",
|
|
572
|
+
)
|
|
573
|
+
.option("--mtc-config-dir <dir>", "Override MTC config root")
|
|
574
|
+
.option("--json", "JSON output")
|
|
575
|
+
.action(async (proposalId, opts) => {
|
|
576
|
+
const db = _dbFromCtx(cc);
|
|
577
|
+
return _bridgeConsume({
|
|
578
|
+
db,
|
|
579
|
+
proposalId,
|
|
580
|
+
multisigDb: opts.multisigDb || defaultMultisigDbPath(),
|
|
581
|
+
multisigLog: opts.multisigLog || defaultMultisigLogPath(),
|
|
582
|
+
json: opts.json,
|
|
583
|
+
mtc: opts.mtc,
|
|
584
|
+
mtcConfigDir: opts.mtcConfigDir,
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
211
588
|
cc.command("bridge-status <bridge-id> <status>")
|
|
212
589
|
.description("Update bridge status")
|
|
213
590
|
.option("-t, --tx-hash <hash>", "Transaction hash")
|
|
@@ -242,6 +619,31 @@ export function registerCrossChainCommand(program) {
|
|
|
242
619
|
if (b.lock_tx_hash) console.log(`Lock TX: ${b.lock_tx_hash}`);
|
|
243
620
|
if (b.mint_tx_hash) console.log(`Mint TX: ${b.mint_tx_hash}`);
|
|
244
621
|
if (b.error_message) console.log(`Error: ${b.error_message}`);
|
|
622
|
+
// #21 B.5 Layer 2 PR1 — surface m-of-n provenance when present.
|
|
623
|
+
if (b.multisig_proposal_id) {
|
|
624
|
+
console.log(`Multisig: ${b.multisig_proposal_id}`);
|
|
625
|
+
try {
|
|
626
|
+
const signers = b.signers_did_json
|
|
627
|
+
? JSON.parse(b.signers_did_json)
|
|
628
|
+
: [];
|
|
629
|
+
const sigs = b.partial_sigs_json
|
|
630
|
+
? JSON.parse(b.partial_sigs_json)
|
|
631
|
+
: [];
|
|
632
|
+
console.log(
|
|
633
|
+
`Signers: ${signers.length} — ${signers.join(", ") || "(none)"}`,
|
|
634
|
+
);
|
|
635
|
+
if (sigs.length) {
|
|
636
|
+
const algs = [...new Set(sigs.map((s) => s.alg))].join("+");
|
|
637
|
+
console.log(`Sigs: ${sigs.length} partial (${algs})`);
|
|
638
|
+
}
|
|
639
|
+
} catch (_err) {
|
|
640
|
+
/* malformed provenance JSON — show raw cell content */
|
|
641
|
+
if (b.signers_did_json)
|
|
642
|
+
console.log(`Signers: ${b.signers_did_json}`);
|
|
643
|
+
if (b.partial_sigs_json)
|
|
644
|
+
console.log(`Sigs: ${b.partial_sigs_json}`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
245
647
|
});
|
|
246
648
|
|
|
247
649
|
cc.command("bridges")
|