aboutsummaryrefslogtreecommitdiffstats
path: root/src/ark/send.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-14 20:12:03 -0700
committerAdam Soltys <[email protected]>2026-08-14 20:12:03 -0700
commit222391a31361e42db713d1737d5a6e15cf8d5ed2 (patch)
tree4bf06a03b11de7ac898b578971372ca7f843e6f9 /src/ark/send.js
parent4bd22c0c45ae35388b2a24e673bedcde5df77961 (diff)
downloadcoinosv3-222391a31361e42db713d1737d5a6e15cf8d5ed2.tar.gz
coinosv3-222391a31361e42db713d1737d5a6e15cf8d5ed2.zip
A send covers itself from as many coins as it needs: one atomic package cosign spends them all, the recipient receives several vtxos, and "consolidate with refresh() first" retires from the vocabulary
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_014tE4U5nEjGTQy8PwYqamfv
Diffstat (limited to 'src/ark/send.js')
-rw-r--r--src/ark/send.js22
1 files changed, 17 insertions, 5 deletions
diff --git a/src/ark/send.js b/src/ark/send.js
index 0e63c7c..f0e471a 100644
--- a/src/ark/send.js
+++ b/src/ark/send.js
@@ -461,13 +461,25 @@ export function combineCosign({ build, nonces, serverResp, vtxoKeys, serverPubke
// full MuSig2 ceremony over the ASP's RequestArkoorCosign
export async function cosignWithServer(ark, build, { input, vtxoKeys, serverPubkey, preimage }) {
- const nonces = genUserNonces(build, vtxoKeys);
+ const [sigs] = await cosignPackageWithServer(ark, [{ build, input, vtxoKeys, preimage }], serverPubkey);
+ return sigs;
+}
+
+// Same ceremony for a PACKAGE of arkoor parts (one per input vtxo) in a single
+// atomic request — the server cosigns all or none, so a multi-input send can't
+// half-spend. Returns one finalSigs array per part, in order.
+export async function cosignPackageWithServer(ark, parts, serverPubkey) {
+ const noncesList = parts.map((p) => genUserNonces(p.build, p.vtxoKeys));
const req = pbWriter();
- req.bytesField(1, cosignPartBytes({ build, input, vtxoKeys, nonces, preimage }));
+ parts.forEach((p, i) => req.bytesField(1, cosignPartBytes({
+ build: p.build, input: p.input, vtxoKeys: p.vtxoKeys, nonces: noncesList[i], preimage: p.preimage,
+ })));
const respBytes = await grpcCall(ark, 'bark_server.ArkService/RequestArkoorCosign', req.finish());
- const [serverResp] = parsePackageCosignResponse(respBytes);
- if (!serverResp) throw new Error('empty cosign response');
- return combineCosign({ build, nonces, serverResp, vtxoKeys, serverPubkey });
+ const resps = parsePackageCosignResponse(respBytes);
+ if (resps.length !== parts.length) throw new Error('bad cosign response count');
+ return parts.map((p, i) => combineCosign({
+ build: p.build, nonces: noncesList[i], serverResp: resps[i], vtxoKeys: p.vtxoKeys, serverPubkey,
+ }));
}
// assemble the final signed Vtxo<Full> bytes for output `idx`, where idx