@toon-protocol/client 0.17.0 → 0.19.0
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/README.md +19 -24
- package/dist/index.d.ts +730 -9
- package/dist/index.js +896 -63
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -153,7 +153,7 @@ async function deriveSolanaKey(seed, accountIndex = 0) {
|
|
|
153
153
|
const { ed25519: ed255194 } = await import("@noble/curves/ed25519.js");
|
|
154
154
|
const encoder = new TextEncoder();
|
|
155
155
|
let I = hmac(sha512, encoder.encode("ed25519 seed"), seed);
|
|
156
|
-
let
|
|
156
|
+
let key2 = I.slice(0, 32);
|
|
157
157
|
let chainCode = I.slice(32);
|
|
158
158
|
const indices = [
|
|
159
159
|
2147483692,
|
|
@@ -168,18 +168,18 @@ async function deriveSolanaKey(seed, accountIndex = 0) {
|
|
|
168
168
|
for (const index of indices) {
|
|
169
169
|
const data = new Uint8Array(37);
|
|
170
170
|
data[0] = 0;
|
|
171
|
-
data.set(
|
|
171
|
+
data.set(key2, 1);
|
|
172
172
|
data[33] = index >>> 24 & 255;
|
|
173
173
|
data[34] = index >>> 16 & 255;
|
|
174
174
|
data[35] = index >>> 8 & 255;
|
|
175
175
|
data[36] = index & 255;
|
|
176
176
|
I = hmac(sha512, chainCode, data);
|
|
177
|
-
|
|
177
|
+
key2 = I.slice(0, 32);
|
|
178
178
|
chainCode = I.slice(32);
|
|
179
179
|
}
|
|
180
|
-
const publicKeyBytes = ed255194.getPublicKey(
|
|
180
|
+
const publicKeyBytes = ed255194.getPublicKey(key2);
|
|
181
181
|
const keypair = new Uint8Array(64);
|
|
182
|
-
keypair.set(
|
|
182
|
+
keypair.set(key2, 0);
|
|
183
183
|
keypair.set(publicKeyBytes, 32);
|
|
184
184
|
const publicKey = toBase58(publicKeyBytes);
|
|
185
185
|
return { secretKey: keypair, publicKey };
|
|
@@ -1309,6 +1309,10 @@ function fulfillmentMatchesCondition(fulfillment, condition) {
|
|
|
1309
1309
|
}
|
|
1310
1310
|
|
|
1311
1311
|
// src/adapters/ilp-send.ts
|
|
1312
|
+
function resolveExpiresAt(expiresAt, timeoutMs) {
|
|
1313
|
+
if (expiresAt === void 0) return new Date(Date.now() + timeoutMs);
|
|
1314
|
+
return expiresAt instanceof Date ? new Date(expiresAt.getTime()) : new Date(expiresAt);
|
|
1315
|
+
}
|
|
1312
1316
|
var FULFILLMENT_MISMATCH_CODE = "F99";
|
|
1313
1317
|
var FULFILLMENT_MISMATCH_MESSAGE = "FULFILL fulfillment does not match execution condition (sha256(fulfillment) != executionCondition) \u2014 packet counted failed";
|
|
1314
1318
|
function mapIlpResponse(packet, sentCondition) {
|
|
@@ -1478,7 +1482,7 @@ var BtpRuntimeClient = class {
|
|
|
1478
1482
|
amount: BigInt(params.amount),
|
|
1479
1483
|
destination: params.destination,
|
|
1480
1484
|
executionCondition: condition ?? new Uint8Array(32),
|
|
1481
|
-
expiresAt: params.expiresAt
|
|
1485
|
+
expiresAt: resolveExpiresAt(params.expiresAt, params.timeout ?? 3e4),
|
|
1482
1486
|
data: fromBase64(params.data)
|
|
1483
1487
|
},
|
|
1484
1488
|
condition
|
|
@@ -1630,7 +1634,7 @@ var HttpIlpClient = class {
|
|
|
1630
1634
|
amount: BigInt(params.amount),
|
|
1631
1635
|
destination: params.destination,
|
|
1632
1636
|
executionCondition: condition ?? new Uint8Array(32),
|
|
1633
|
-
expiresAt: params.expiresAt
|
|
1637
|
+
expiresAt: resolveExpiresAt(params.expiresAt, requestTimeout),
|
|
1634
1638
|
data: fromBase64(params.data)
|
|
1635
1639
|
});
|
|
1636
1640
|
const headers = {
|
|
@@ -1734,17 +1738,17 @@ function readDiscoveredIlpPeer(peer) {
|
|
|
1734
1738
|
}
|
|
1735
1739
|
function selectIlpTransport(peer, options = {}) {
|
|
1736
1740
|
const needsDuplex = options.needsDuplex ?? false;
|
|
1737
|
-
const
|
|
1741
|
+
const http4 = peer.httpEndpoint?.trim() || void 0;
|
|
1738
1742
|
const btp = peer.btpEndpoint?.trim() || void 0;
|
|
1739
1743
|
const canUpgrade = peer.supportsUpgrade === true;
|
|
1740
1744
|
if (needsDuplex) {
|
|
1741
1745
|
if (btp) return { kind: "btp", btpEndpoint: btp };
|
|
1742
|
-
if (
|
|
1746
|
+
if (http4 && canUpgrade) return { kind: "http-upgradable", httpEndpoint: http4 };
|
|
1743
1747
|
throw new Error(
|
|
1744
1748
|
"Duplex transport required but peer exposes neither a btpEndpoint nor an upgradable httpEndpoint"
|
|
1745
1749
|
);
|
|
1746
1750
|
}
|
|
1747
|
-
if (
|
|
1751
|
+
if (http4) return { kind: "http", httpEndpoint: http4, canUpgrade };
|
|
1748
1752
|
if (btp) return { kind: "btp", btpEndpoint: btp };
|
|
1749
1753
|
throw new Error("Peer exposes neither an httpEndpoint nor a btpEndpoint");
|
|
1750
1754
|
}
|
|
@@ -1965,13 +1969,13 @@ async function buildAndSendTransaction(rpcUrl, feePayer, instructions, additiona
|
|
|
1965
1969
|
isWritable: true
|
|
1966
1970
|
});
|
|
1967
1971
|
for (const ix of instructions) {
|
|
1968
|
-
for (const
|
|
1969
|
-
const existing = accountMap.get(
|
|
1972
|
+
for (const key2 of ix.keys) {
|
|
1973
|
+
const existing = accountMap.get(key2.pubkey);
|
|
1970
1974
|
if (existing) {
|
|
1971
|
-
existing.isSigner = existing.isSigner ||
|
|
1972
|
-
existing.isWritable = existing.isWritable ||
|
|
1975
|
+
existing.isSigner = existing.isSigner || key2.isSigner;
|
|
1976
|
+
existing.isWritable = existing.isWritable || key2.isWritable;
|
|
1973
1977
|
} else {
|
|
1974
|
-
accountMap.set(
|
|
1978
|
+
accountMap.set(key2.pubkey, { ...key2 });
|
|
1975
1979
|
}
|
|
1976
1980
|
}
|
|
1977
1981
|
if (!accountMap.has(ix.programId)) {
|
|
@@ -3405,7 +3409,14 @@ async function buildMinaPaymentChannelProof(params) {
|
|
|
3405
3409
|
}
|
|
3406
3410
|
|
|
3407
3411
|
// src/channel/mina-deposit.ts
|
|
3408
|
-
var
|
|
3412
|
+
var CHANNEL_STATE_INDEX = {
|
|
3413
|
+
channelHash: 0,
|
|
3414
|
+
balanceCommitment: 1,
|
|
3415
|
+
nonceField: 2,
|
|
3416
|
+
channelState: 3,
|
|
3417
|
+
depositTotal: 4
|
|
3418
|
+
};
|
|
3419
|
+
var DEPOSIT_TOTAL_STATE_INDEX = CHANNEL_STATE_INDEX.depositTotal;
|
|
3409
3420
|
async function readMinaDepositTotal(graphqlUrl, zkAppAddress, fetchImpl = fetch) {
|
|
3410
3421
|
const query = "query($pk:String!){account(publicKey:$pk){zkappState}}";
|
|
3411
3422
|
const res = await fetchImpl(graphqlUrl, {
|
|
@@ -3430,6 +3441,42 @@ async function readMinaDepositTotal(graphqlUrl, zkAppAddress, fetchImpl = fetch)
|
|
|
3430
3441
|
}
|
|
3431
3442
|
return BigInt(state[DEPOSIT_TOTAL_STATE_INDEX]);
|
|
3432
3443
|
}
|
|
3444
|
+
var MINA_CHANNEL_STATE = {
|
|
3445
|
+
UNINITIALIZED: 0,
|
|
3446
|
+
OPEN: 1,
|
|
3447
|
+
CLOSING: 2,
|
|
3448
|
+
SETTLED: 3
|
|
3449
|
+
};
|
|
3450
|
+
async function readMinaChannelState(graphqlUrl, zkAppAddress, fetchImpl = fetch) {
|
|
3451
|
+
const query = "query($pk:String!){account(publicKey:$pk){zkappState}}";
|
|
3452
|
+
const res = await fetchImpl(graphqlUrl, {
|
|
3453
|
+
method: "POST",
|
|
3454
|
+
headers: { "content-type": "application/json" },
|
|
3455
|
+
body: JSON.stringify({ query, variables: { pk: zkAppAddress } })
|
|
3456
|
+
});
|
|
3457
|
+
if (!res.ok) {
|
|
3458
|
+
throw new Error(`Mina GraphQL request failed: HTTP ${res.status}`);
|
|
3459
|
+
}
|
|
3460
|
+
const json = await res.json();
|
|
3461
|
+
if (json.errors && json.errors.length > 0) {
|
|
3462
|
+
throw new Error(
|
|
3463
|
+
`Mina GraphQL error: ${json.errors[0]?.message ?? "unknown"}`
|
|
3464
|
+
);
|
|
3465
|
+
}
|
|
3466
|
+
const state = json.data?.account?.zkappState;
|
|
3467
|
+
if (!state || state.length <= DEPOSIT_TOTAL_STATE_INDEX) {
|
|
3468
|
+
throw new Error(
|
|
3469
|
+
`Mina zkApp ${zkAppAddress} has no readable zkappState (account not found or not a zkApp)`
|
|
3470
|
+
);
|
|
3471
|
+
}
|
|
3472
|
+
return {
|
|
3473
|
+
channelHash: String(state[CHANNEL_STATE_INDEX.channelHash]),
|
|
3474
|
+
balanceCommitment: String(state[CHANNEL_STATE_INDEX.balanceCommitment]),
|
|
3475
|
+
nonceField: BigInt(state[CHANNEL_STATE_INDEX.nonceField]),
|
|
3476
|
+
channelState: Number(state[CHANNEL_STATE_INDEX.channelState]),
|
|
3477
|
+
depositTotal: BigInt(state[CHANNEL_STATE_INDEX.depositTotal])
|
|
3478
|
+
};
|
|
3479
|
+
}
|
|
3433
3480
|
|
|
3434
3481
|
// src/signing/mina-signer.ts
|
|
3435
3482
|
var DEFAULT_MINA_TOKEN_ID = "MINA";
|
|
@@ -4267,8 +4314,8 @@ async function requestBlobStorage(client, secretKey, params) {
|
|
|
4267
4314
|
};
|
|
4268
4315
|
}
|
|
4269
4316
|
function extractArweaveTxId(base64Data) {
|
|
4270
|
-
const
|
|
4271
|
-
if (!
|
|
4317
|
+
const http4 = parseFulfillHttp(base64Data);
|
|
4318
|
+
if (!http4.isHttp) {
|
|
4272
4319
|
const legacy = decodeUtf8(fromBase64(base64Data));
|
|
4273
4320
|
if (!ARWEAVE_TX_ID_REGEX.test(legacy)) {
|
|
4274
4321
|
throw new Error(
|
|
@@ -4277,18 +4324,18 @@ function extractArweaveTxId(base64Data) {
|
|
|
4277
4324
|
}
|
|
4278
4325
|
return legacy;
|
|
4279
4326
|
}
|
|
4280
|
-
if (
|
|
4281
|
-
const detail =
|
|
4327
|
+
if (http4.status < 200 || http4.status >= 300) {
|
|
4328
|
+
const detail = http4.body ? ` - ${http4.body}` : "";
|
|
4282
4329
|
throw new Error(
|
|
4283
|
-
`Blob upload failed: DVM returned HTTP ${
|
|
4330
|
+
`Blob upload failed: DVM returned HTTP ${http4.status} ${http4.statusText}`.trimEnd() + detail
|
|
4284
4331
|
);
|
|
4285
4332
|
}
|
|
4286
4333
|
let parsed;
|
|
4287
4334
|
try {
|
|
4288
|
-
parsed = JSON.parse(
|
|
4335
|
+
parsed = JSON.parse(http4.body);
|
|
4289
4336
|
} catch {
|
|
4290
4337
|
throw new Error(
|
|
4291
|
-
`Blob upload response body was not valid JSON: "${
|
|
4338
|
+
`Blob upload response body was not valid JSON: "${http4.body}"`
|
|
4292
4339
|
);
|
|
4293
4340
|
}
|
|
4294
4341
|
const body = parsed;
|
|
@@ -4306,7 +4353,7 @@ function extractArweaveTxId(base64Data) {
|
|
|
4306
4353
|
}
|
|
4307
4354
|
}
|
|
4308
4355
|
throw new Error(
|
|
4309
|
-
`Blob upload response did not contain a valid Arweave tx ID: "${
|
|
4356
|
+
`Blob upload response did not contain a valid Arweave tx ID: "${http4.body}"`
|
|
4310
4357
|
);
|
|
4311
4358
|
}
|
|
4312
4359
|
|
|
@@ -4561,7 +4608,431 @@ function parseHttpResponse(bytes) {
|
|
|
4561
4608
|
);
|
|
4562
4609
|
}
|
|
4563
4610
|
|
|
4611
|
+
// src/swap/settle-received-claims.ts
|
|
4612
|
+
import {
|
|
4613
|
+
buildSettlementTx,
|
|
4614
|
+
SettlementTxError
|
|
4615
|
+
} from "@toon-protocol/sdk";
|
|
4616
|
+
import {
|
|
4617
|
+
createPublicClient as createPublicClient3,
|
|
4618
|
+
defineChain as defineChain3,
|
|
4619
|
+
fromRlp,
|
|
4620
|
+
http as http3
|
|
4621
|
+
} from "viem";
|
|
4622
|
+
function entryToAccumulatedClaim(entry) {
|
|
4623
|
+
return {
|
|
4624
|
+
packetIndex: 0,
|
|
4625
|
+
sourceAmount: 0n,
|
|
4626
|
+
targetAmount: entry.cumulativeAmount,
|
|
4627
|
+
claimBytes: entry.claimBytes,
|
|
4628
|
+
swapEphemeralPubkey: "",
|
|
4629
|
+
...entry.claimId !== void 0 ? { claimId: entry.claimId } : {},
|
|
4630
|
+
pair: entry.pair,
|
|
4631
|
+
receivedAt: entry.receivedAt,
|
|
4632
|
+
channelId: entry.channelId,
|
|
4633
|
+
nonce: entry.nonce.toString(),
|
|
4634
|
+
cumulativeAmount: entry.cumulativeAmount.toString(),
|
|
4635
|
+
recipient: entry.recipient,
|
|
4636
|
+
swapSignerAddress: entry.swapSignerAddress
|
|
4637
|
+
};
|
|
4638
|
+
}
|
|
4639
|
+
function parseEvmChainId2(chain) {
|
|
4640
|
+
const parts = chain.split(":");
|
|
4641
|
+
const raw = parts.length >= 3 ? parts[2] : parts[1];
|
|
4642
|
+
const chainId = Number.parseInt(raw ?? "", 10);
|
|
4643
|
+
return Number.isInteger(chainId) && chainId > 0 ? chainId : void 0;
|
|
4644
|
+
}
|
|
4645
|
+
function buildSwapSettlements(params) {
|
|
4646
|
+
return params.entries.map((entry) => {
|
|
4647
|
+
const base = { chain: entry.chain, channelId: entry.channelId };
|
|
4648
|
+
const signer = { address: entry.swapSignerAddress };
|
|
4649
|
+
const contract = params.tokenNetworks?.[entry.chain];
|
|
4650
|
+
if (entry.chain.startsWith("evm")) {
|
|
4651
|
+
const chainId = parseEvmChainId2(entry.chain);
|
|
4652
|
+
if (!contract || chainId === void 0) {
|
|
4653
|
+
return {
|
|
4654
|
+
...base,
|
|
4655
|
+
error: {
|
|
4656
|
+
code: "MISSING_CHAIN_CONFIG",
|
|
4657
|
+
message: `EVM settlement for ${entry.chain} needs tokenNetworks["${entry.chain}"] (TokenNetwork contract) and a numeric chain id in the chain key.`
|
|
4658
|
+
}
|
|
4659
|
+
};
|
|
4660
|
+
}
|
|
4661
|
+
signer.contractAddress = contract;
|
|
4662
|
+
signer.chainId = chainId;
|
|
4663
|
+
} else if (entry.chain.startsWith("solana")) {
|
|
4664
|
+
if (!contract) {
|
|
4665
|
+
return {
|
|
4666
|
+
...base,
|
|
4667
|
+
error: {
|
|
4668
|
+
code: "MISSING_CHAIN_CONFIG",
|
|
4669
|
+
message: `Solana settlement for ${entry.chain} needs tokenNetworks["${entry.chain}"] (programId).`
|
|
4670
|
+
}
|
|
4671
|
+
};
|
|
4672
|
+
}
|
|
4673
|
+
signer.programId = contract;
|
|
4674
|
+
}
|
|
4675
|
+
try {
|
|
4676
|
+
const result = buildSettlementTx({
|
|
4677
|
+
claims: [entryToAccumulatedClaim(entry)],
|
|
4678
|
+
signers: { [entry.chain]: signer },
|
|
4679
|
+
recipients: { [entry.chain]: entry.recipient },
|
|
4680
|
+
...params.minaSignerClient ? { minaSignerClient: params.minaSignerClient } : {}
|
|
4681
|
+
});
|
|
4682
|
+
const firstRejected = result.rejected[0];
|
|
4683
|
+
if (firstRejected) {
|
|
4684
|
+
return {
|
|
4685
|
+
...base,
|
|
4686
|
+
error: {
|
|
4687
|
+
code: firstRejected.reason,
|
|
4688
|
+
message: firstRejected.details ?? `stored claim for ${entry.chain}/${entry.channelId} failed settlement re-verification`
|
|
4689
|
+
}
|
|
4690
|
+
};
|
|
4691
|
+
}
|
|
4692
|
+
const bundle = result.bundles[0];
|
|
4693
|
+
if (!bundle) {
|
|
4694
|
+
return {
|
|
4695
|
+
...base,
|
|
4696
|
+
error: {
|
|
4697
|
+
code: "NO_BUNDLE",
|
|
4698
|
+
message: `buildSettlementTx produced no bundle for ${entry.chain}/${entry.channelId}`
|
|
4699
|
+
}
|
|
4700
|
+
};
|
|
4701
|
+
}
|
|
4702
|
+
return { ...base, bundle };
|
|
4703
|
+
} catch (err) {
|
|
4704
|
+
const code = err instanceof SettlementTxError ? err.code : "BUILD_FAILED";
|
|
4705
|
+
return {
|
|
4706
|
+
...base,
|
|
4707
|
+
error: {
|
|
4708
|
+
code,
|
|
4709
|
+
message: err instanceof Error ? err.message : String(err)
|
|
4710
|
+
}
|
|
4711
|
+
};
|
|
4712
|
+
}
|
|
4713
|
+
});
|
|
4714
|
+
}
|
|
4715
|
+
function decodeEvmSettlementTx(bundle) {
|
|
4716
|
+
const fields = fromRlp(bundle.unsignedTxBytes, "hex");
|
|
4717
|
+
if (!Array.isArray(fields) || fields.length !== 9) {
|
|
4718
|
+
throw new Error(
|
|
4719
|
+
`settlement bundle RLP is not a 9-field unsigned EVM tx (got ${Array.isArray(fields) ? fields.length : typeof fields})`
|
|
4720
|
+
);
|
|
4721
|
+
}
|
|
4722
|
+
const to = fields[3];
|
|
4723
|
+
const data = fields[5];
|
|
4724
|
+
const chainIdHex = fields[6];
|
|
4725
|
+
const chainId = Number.parseInt(chainIdHex === "0x" ? "0x0" : chainIdHex, 16);
|
|
4726
|
+
if (typeof to !== "string" || to.length !== 42) {
|
|
4727
|
+
throw new Error(`settlement tx "to" is not a 20-byte address: ${String(to)}`);
|
|
4728
|
+
}
|
|
4729
|
+
return { to, data: data === "0x" ? "0x" : data, chainId };
|
|
4730
|
+
}
|
|
4731
|
+
async function submitEvmSettlement(bundle, params) {
|
|
4732
|
+
if (bundle.chainKind !== "evm") {
|
|
4733
|
+
throw new Error(
|
|
4734
|
+
`submitEvmSettlement only submits evm bundles (got ${bundle.chainKind} for ${bundle.chain})`
|
|
4735
|
+
);
|
|
4736
|
+
}
|
|
4737
|
+
const { to, data, chainId } = decodeEvmSettlementTx(bundle);
|
|
4738
|
+
const chain = defineChain3({
|
|
4739
|
+
id: chainId,
|
|
4740
|
+
name: bundle.chain,
|
|
4741
|
+
nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
|
|
4742
|
+
rpcUrls: { default: { http: [params.rpcUrl] } }
|
|
4743
|
+
});
|
|
4744
|
+
const publicClient = createPublicClient3({ chain, transport: http3(params.rpcUrl) });
|
|
4745
|
+
const [nonce, gasPrice, gas] = await Promise.all([
|
|
4746
|
+
publicClient.getTransactionCount({
|
|
4747
|
+
address: params.account.address,
|
|
4748
|
+
blockTag: "pending"
|
|
4749
|
+
}),
|
|
4750
|
+
publicClient.getGasPrice(),
|
|
4751
|
+
publicClient.estimateGas({ account: params.account.address, to, data })
|
|
4752
|
+
]);
|
|
4753
|
+
const signed = await params.account.signTransaction({
|
|
4754
|
+
type: "legacy",
|
|
4755
|
+
chainId,
|
|
4756
|
+
nonce,
|
|
4757
|
+
gasPrice,
|
|
4758
|
+
gas,
|
|
4759
|
+
to,
|
|
4760
|
+
value: 0n,
|
|
4761
|
+
data
|
|
4762
|
+
});
|
|
4763
|
+
const txHash = await publicClient.sendRawTransaction({
|
|
4764
|
+
serializedTransaction: signed
|
|
4765
|
+
});
|
|
4766
|
+
try {
|
|
4767
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
4768
|
+
hash: txHash,
|
|
4769
|
+
timeout: params.timeoutMs ?? 6e4
|
|
4770
|
+
});
|
|
4771
|
+
return { txHash, status: receipt.status };
|
|
4772
|
+
} catch {
|
|
4773
|
+
return { txHash };
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4777
|
+
// src/swap/mina-settlement.ts
|
|
4778
|
+
import { hexToMinaBase58PrivateKey as hexToMinaBase58PrivateKey4 } from "@toon-protocol/core";
|
|
4779
|
+
var MinaSettlementError = class extends Error {
|
|
4780
|
+
code;
|
|
4781
|
+
constructor(code, message) {
|
|
4782
|
+
super(`${code}: ${message}`);
|
|
4783
|
+
this.name = "MinaSettlementError";
|
|
4784
|
+
this.code = code;
|
|
4785
|
+
}
|
|
4786
|
+
};
|
|
4787
|
+
function parseProofSignature(proofJson) {
|
|
4788
|
+
const parsed = JSON.parse(proofJson);
|
|
4789
|
+
const r = parsed.signature?.r;
|
|
4790
|
+
const s = parsed.signature?.s;
|
|
4791
|
+
if (typeof r !== "string" || typeof s !== "string") {
|
|
4792
|
+
throw new Error("recipient co-signature proof did not carry string r/s");
|
|
4793
|
+
}
|
|
4794
|
+
return { r, s };
|
|
4795
|
+
}
|
|
4796
|
+
async function buildMinaCoSignedClaim(inputs) {
|
|
4797
|
+
const channelNonce = inputs.channelNonce ?? 0n;
|
|
4798
|
+
const salt = inputs.saltOverride ?? deriveMinaSalt(inputs.channelId, Number(inputs.nonce));
|
|
4799
|
+
if (inputs.cumulativeAmount > inputs.depositTotal) {
|
|
4800
|
+
throw new MinaSettlementError(
|
|
4801
|
+
"CUMULATIVE_EXCEEDS_DEPOSIT",
|
|
4802
|
+
`claim cumulativeAmount (${inputs.cumulativeAmount}) exceeds the channel depositTotal (${inputs.depositTotal}) \u2014 cannot conserve balances`
|
|
4803
|
+
);
|
|
4804
|
+
}
|
|
4805
|
+
const { Poseidon, PublicKey } = await loadMinaPaymentChannelBindings();
|
|
4806
|
+
const hashRecipientFirst = minaParticipantChannelHashField(
|
|
4807
|
+
Poseidon,
|
|
4808
|
+
PublicKey,
|
|
4809
|
+
inputs.recipient,
|
|
4810
|
+
inputs.swapSignerAddress,
|
|
4811
|
+
channelNonce
|
|
4812
|
+
).toString();
|
|
4813
|
+
const hashMakerFirst = minaParticipantChannelHashField(
|
|
4814
|
+
Poseidon,
|
|
4815
|
+
PublicKey,
|
|
4816
|
+
inputs.swapSignerAddress,
|
|
4817
|
+
inputs.recipient,
|
|
4818
|
+
channelNonce
|
|
4819
|
+
).toString();
|
|
4820
|
+
let participantA;
|
|
4821
|
+
let participantB;
|
|
4822
|
+
let recipientRole;
|
|
4823
|
+
if (hashRecipientFirst === inputs.onChainChannelHash) {
|
|
4824
|
+
participantA = inputs.recipient;
|
|
4825
|
+
participantB = inputs.swapSignerAddress;
|
|
4826
|
+
recipientRole = "A";
|
|
4827
|
+
} else if (hashMakerFirst === inputs.onChainChannelHash) {
|
|
4828
|
+
participantA = inputs.swapSignerAddress;
|
|
4829
|
+
participantB = inputs.recipient;
|
|
4830
|
+
recipientRole = "B";
|
|
4831
|
+
} else {
|
|
4832
|
+
throw new MinaSettlementError(
|
|
4833
|
+
"CHANNEL_HASH_MISMATCH",
|
|
4834
|
+
`neither ordering of recipient ${inputs.recipient} / maker ${inputs.swapSignerAddress} reproduces the on-chain channelHash ${inputs.onChainChannelHash} (channelNonce ${channelNonce})`
|
|
4835
|
+
);
|
|
4836
|
+
}
|
|
4837
|
+
const recipientBalance = inputs.cumulativeAmount;
|
|
4838
|
+
const makerBalance = inputs.depositTotal - inputs.cumulativeAmount;
|
|
4839
|
+
const balanceA = recipientRole === "A" ? recipientBalance : makerBalance;
|
|
4840
|
+
const balanceB = inputs.depositTotal - balanceA;
|
|
4841
|
+
const balanceCommitment = minaBalanceCommitment(
|
|
4842
|
+
Poseidon,
|
|
4843
|
+
balanceA,
|
|
4844
|
+
balanceB,
|
|
4845
|
+
salt
|
|
4846
|
+
).toString();
|
|
4847
|
+
const recipientPrivateKeyBase58 = hexToMinaBase58PrivateKey4(
|
|
4848
|
+
inputs.recipientPrivateKey
|
|
4849
|
+
);
|
|
4850
|
+
const built = await buildMinaPaymentChannelProof({
|
|
4851
|
+
zkAppAddress: inputs.channelId,
|
|
4852
|
+
minaPrivateKeyBase58: recipientPrivateKeyBase58,
|
|
4853
|
+
signerPublicKey: inputs.recipient,
|
|
4854
|
+
balanceA,
|
|
4855
|
+
balanceB,
|
|
4856
|
+
salt,
|
|
4857
|
+
nonce: inputs.nonce,
|
|
4858
|
+
participantA,
|
|
4859
|
+
participantB,
|
|
4860
|
+
channelNonce,
|
|
4861
|
+
proofEncoding: "json"
|
|
4862
|
+
});
|
|
4863
|
+
if (built.balanceCommitment !== balanceCommitment) {
|
|
4864
|
+
throw new Error(
|
|
4865
|
+
`co-sign commitment drift: builder ${built.balanceCommitment} != ${balanceCommitment}`
|
|
4866
|
+
);
|
|
4867
|
+
}
|
|
4868
|
+
const recipientSignature = parseProofSignature(built.proof);
|
|
4869
|
+
const signatureA = recipientRole === "A" ? recipientSignature : inputs.makerSignature;
|
|
4870
|
+
const signatureB = recipientRole === "B" ? recipientSignature : inputs.makerSignature;
|
|
4871
|
+
return {
|
|
4872
|
+
channelId: inputs.channelId,
|
|
4873
|
+
balanceA,
|
|
4874
|
+
balanceB,
|
|
4875
|
+
salt,
|
|
4876
|
+
nonce: inputs.nonce,
|
|
4877
|
+
channelNonce,
|
|
4878
|
+
balanceCommitment,
|
|
4879
|
+
participantA,
|
|
4880
|
+
participantB,
|
|
4881
|
+
recipientRole,
|
|
4882
|
+
recipientSignature,
|
|
4883
|
+
...signatureA ? { signatureA } : {},
|
|
4884
|
+
...signatureB ? { signatureB } : {},
|
|
4885
|
+
makerSignatureMissing: inputs.makerSignature === void 0
|
|
4886
|
+
};
|
|
4887
|
+
}
|
|
4888
|
+
async function submitMinaSettlement(bundle, context) {
|
|
4889
|
+
if (bundle.chainKind !== "mina") {
|
|
4890
|
+
throw new MinaSettlementError(
|
|
4891
|
+
"NOT_MINA_BUNDLE",
|
|
4892
|
+
`submitMinaSettlement only settles mina bundles (got ${bundle.chainKind} for ${bundle.chain})`
|
|
4893
|
+
);
|
|
4894
|
+
}
|
|
4895
|
+
if (!context.graphqlUrl) {
|
|
4896
|
+
throw new MinaSettlementError(
|
|
4897
|
+
"NO_GRAPHQL_CONFIGURED",
|
|
4898
|
+
`no Mina graphqlUrl configured for "${bundle.chain}" \u2014 set minaChannel.graphqlUrl to enable receive-side settlement.`
|
|
4899
|
+
);
|
|
4900
|
+
}
|
|
4901
|
+
const graphqlUrl = context.graphqlUrl;
|
|
4902
|
+
const channelNonce = context.channelNonce ?? 0n;
|
|
4903
|
+
const nonce = BigInt(bundle.nonce);
|
|
4904
|
+
const cumulativeAmount = BigInt(bundle.cumulativeAmount);
|
|
4905
|
+
const read = context.reader ?? readMinaChannelState;
|
|
4906
|
+
const state = await read(graphqlUrl, bundle.channelId);
|
|
4907
|
+
if (state.channelState !== MINA_CHANNEL_STATE.OPEN) {
|
|
4908
|
+
throw new MinaSettlementError(
|
|
4909
|
+
"CHANNEL_NOT_OPEN",
|
|
4910
|
+
`channel ${bundle.channelId} is not OPEN (channelState=${state.channelState}); claimFromChannel only applies to an OPEN channel.`
|
|
4911
|
+
);
|
|
4912
|
+
}
|
|
4913
|
+
if (nonce <= state.nonceField) {
|
|
4914
|
+
throw new MinaSettlementError(
|
|
4915
|
+
"NONCE_NOT_ADVANCING",
|
|
4916
|
+
`claim nonce ${nonce} does not advance the on-chain nonceField ${state.nonceField} for ${bundle.channelId} (already claimed).`
|
|
4917
|
+
);
|
|
4918
|
+
}
|
|
4919
|
+
const claim = await buildMinaCoSignedClaim({
|
|
4920
|
+
channelId: bundle.channelId,
|
|
4921
|
+
nonce,
|
|
4922
|
+
cumulativeAmount,
|
|
4923
|
+
recipient: bundle.recipient,
|
|
4924
|
+
swapSignerAddress: bundle.swapSignerAddress,
|
|
4925
|
+
depositTotal: state.depositTotal,
|
|
4926
|
+
onChainChannelHash: state.channelHash,
|
|
4927
|
+
recipientPrivateKey: context.recipientPrivateKey,
|
|
4928
|
+
channelNonce,
|
|
4929
|
+
...context.makerSignature ? { makerSignature: context.makerSignature } : {}
|
|
4930
|
+
});
|
|
4931
|
+
if (claim.makerSignatureMissing || !claim.signatureA || !claim.signatureB) {
|
|
4932
|
+
throw new MinaSettlementError(
|
|
4933
|
+
"MINA_MAKER_COSIGN_REQUIRED",
|
|
4934
|
+
`on-chain claimFromChannel is dual-party: it needs the maker's payment-channel-commitment signature over [commitment, nonce, channelHash] in addition to the recipient's co-signature. The swap-wire claim only carries the maker's balanceProofFieldsMina signature (a different message), so the maker must additionally deliver an on-chain-form co-signature. Recipient co-signature assembled and ready (${bundle.channelId} nonce ${nonce}).`
|
|
4935
|
+
);
|
|
4936
|
+
}
|
|
4937
|
+
const submitter = context.submitter ?? createO1jsMinaClaimSubmitter();
|
|
4938
|
+
const { txHash } = await submitter.claimFromChannel({
|
|
4939
|
+
graphqlUrl,
|
|
4940
|
+
channelId: bundle.channelId,
|
|
4941
|
+
balanceA: claim.balanceA,
|
|
4942
|
+
balanceB: claim.balanceB,
|
|
4943
|
+
salt: claim.salt,
|
|
4944
|
+
nonce: claim.nonce,
|
|
4945
|
+
participantA: claim.participantA,
|
|
4946
|
+
participantB: claim.participantB,
|
|
4947
|
+
channelNonce: claim.channelNonce,
|
|
4948
|
+
signatureA: claim.signatureA,
|
|
4949
|
+
signatureB: claim.signatureB,
|
|
4950
|
+
feePayerPrivateKey: context.feePayerPrivateKey ?? context.recipientPrivateKey,
|
|
4951
|
+
...context.txFeeNanomina !== void 0 ? { txFeeNanomina: context.txFeeNanomina } : {}
|
|
4952
|
+
});
|
|
4953
|
+
return { txHash };
|
|
4954
|
+
}
|
|
4955
|
+
var DEFAULT_MINA_TX_FEE_NANOMINA = 100000000n;
|
|
4956
|
+
function createO1jsMinaClaimSubmitter() {
|
|
4957
|
+
return {
|
|
4958
|
+
async claimFromChannel(args) {
|
|
4959
|
+
try {
|
|
4960
|
+
const o1js = await import("o1js");
|
|
4961
|
+
const {
|
|
4962
|
+
Mina,
|
|
4963
|
+
PrivateKey,
|
|
4964
|
+
PublicKey,
|
|
4965
|
+
Field,
|
|
4966
|
+
Poseidon,
|
|
4967
|
+
Signature,
|
|
4968
|
+
fetchAccount
|
|
4969
|
+
} = o1js;
|
|
4970
|
+
const zkAppMod = await import("@toon-protocol/mina-zkapp");
|
|
4971
|
+
const PaymentChannel = zkAppMod.PaymentChannel;
|
|
4972
|
+
Mina.setActiveInstance(Mina.Network(args.graphqlUrl));
|
|
4973
|
+
const feePayerKey = PrivateKey.fromBase58(
|
|
4974
|
+
hexToMinaBase58PrivateKey4(args.feePayerPrivateKey)
|
|
4975
|
+
);
|
|
4976
|
+
const feePayerPub = feePayerKey.toPublicKey();
|
|
4977
|
+
await PaymentChannel.compile();
|
|
4978
|
+
const zkAppPub = PublicKey.fromBase58(args.channelId);
|
|
4979
|
+
await fetchAccount({ publicKey: zkAppPub });
|
|
4980
|
+
await fetchAccount({ publicKey: feePayerPub });
|
|
4981
|
+
const zkApp = new PaymentChannel(zkAppPub);
|
|
4982
|
+
const balA = Field(args.balanceA);
|
|
4983
|
+
const balB = Field(args.balanceB);
|
|
4984
|
+
const saltField = Field(args.salt);
|
|
4985
|
+
const newNonce = Field(args.nonce);
|
|
4986
|
+
const channelNonce = Field(args.channelNonce);
|
|
4987
|
+
const newBalanceCommitment = Poseidon.hash([balA, balB, saltField]);
|
|
4988
|
+
const sigA = Signature.fromJSON({
|
|
4989
|
+
r: args.signatureA.r,
|
|
4990
|
+
s: args.signatureA.s
|
|
4991
|
+
});
|
|
4992
|
+
const sigB = Signature.fromJSON({
|
|
4993
|
+
r: args.signatureB.r,
|
|
4994
|
+
s: args.signatureB.s
|
|
4995
|
+
});
|
|
4996
|
+
const partA = PublicKey.fromBase58(args.participantA);
|
|
4997
|
+
const partB = PublicKey.fromBase58(args.participantB);
|
|
4998
|
+
const fee = (args.txFeeNanomina ?? DEFAULT_MINA_TX_FEE_NANOMINA).toString();
|
|
4999
|
+
const txn = await Mina.transaction(
|
|
5000
|
+
{ sender: feePayerPub, fee },
|
|
5001
|
+
async () => {
|
|
5002
|
+
await zkApp.claimFromChannel(
|
|
5003
|
+
balA,
|
|
5004
|
+
balB,
|
|
5005
|
+
saltField,
|
|
5006
|
+
sigA,
|
|
5007
|
+
sigB,
|
|
5008
|
+
partA,
|
|
5009
|
+
partB,
|
|
5010
|
+
channelNonce,
|
|
5011
|
+
newBalanceCommitment,
|
|
5012
|
+
newNonce
|
|
5013
|
+
);
|
|
5014
|
+
}
|
|
5015
|
+
);
|
|
5016
|
+
await txn.prove();
|
|
5017
|
+
const sent = await txn.sign([feePayerKey]).send();
|
|
5018
|
+
return { txHash: sent.hash ?? "" };
|
|
5019
|
+
} catch (err) {
|
|
5020
|
+
throw new MinaSettlementError(
|
|
5021
|
+
"PROVING_FAILED",
|
|
5022
|
+
err instanceof Error ? err.message : String(err)
|
|
5023
|
+
);
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
};
|
|
5027
|
+
}
|
|
5028
|
+
|
|
4564
5029
|
// src/ToonClient.ts
|
|
5030
|
+
function parseMakerMinaSignature(raw) {
|
|
5031
|
+
if (raw && typeof raw.r === "string" && raw.r.length > 0 && typeof raw.s === "string" && raw.s.length > 0) {
|
|
5032
|
+
return { r: raw.r, s: raw.s };
|
|
5033
|
+
}
|
|
5034
|
+
return void 0;
|
|
5035
|
+
}
|
|
4565
5036
|
var ToonClient = class {
|
|
4566
5037
|
config;
|
|
4567
5038
|
state = null;
|
|
@@ -4846,34 +5317,11 @@ var ToonClient = class {
|
|
|
4846
5317
|
const writeData = buildStoreWriteEnvelope(event, options?.proxyPath);
|
|
4847
5318
|
const destination = options?.destination ?? this.config.destinationAddress;
|
|
4848
5319
|
const transport = this.getClaimTransport();
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
const negotiation = this.peerNegotiations.get(peerId);
|
|
4855
|
-
if (!negotiation) {
|
|
4856
|
-
throw new ToonClientError(
|
|
4857
|
-
`No negotiation metadata for peer "${peerId}" \u2014 was bootstrap completed?`,
|
|
4858
|
-
"PEER_NOT_NEGOTIATED"
|
|
4859
|
-
);
|
|
4860
|
-
}
|
|
4861
|
-
const channelId = await this.channelManager.ensureChannel(
|
|
4862
|
-
peerId,
|
|
4863
|
-
negotiation
|
|
4864
|
-
);
|
|
4865
|
-
const proof = await this.channelManager.signBalanceProof(
|
|
4866
|
-
channelId,
|
|
4867
|
-
BigInt(amount)
|
|
4868
|
-
);
|
|
4869
|
-
const signer = this.channelManager.getSignerForChannel(channelId);
|
|
4870
|
-
claimMessage = signer.buildClaimMessage(proof, this.getPublicKey());
|
|
4871
|
-
} else {
|
|
4872
|
-
throw new ToonClientError(
|
|
4873
|
-
"No claim provided and no channel manager configured",
|
|
4874
|
-
"MISSING_CLAIM"
|
|
4875
|
-
);
|
|
4876
|
-
}
|
|
5320
|
+
const claimMessage = await this.resolveClaimForDestination(
|
|
5321
|
+
destination,
|
|
5322
|
+
BigInt(amount),
|
|
5323
|
+
options?.claim
|
|
5324
|
+
);
|
|
4877
5325
|
const response = await transport.sendIlpPacketWithClaim(
|
|
4878
5326
|
{
|
|
4879
5327
|
destination,
|
|
@@ -5080,8 +5528,6 @@ var ToonClient = class {
|
|
|
5080
5528
|
}
|
|
5081
5529
|
/**
|
|
5082
5530
|
* Shared claim-resolution logic used by `publishEvent` and `sendSwapPacket`.
|
|
5083
|
-
* TODO(12.5 followup): also factor `publishEvent`'s inline claim resolution
|
|
5084
|
-
* to call this helper. Kept duplicated for now to minimize regression risk.
|
|
5085
5531
|
*/
|
|
5086
5532
|
async resolveClaimForDestination(destination, amount, explicitClaim) {
|
|
5087
5533
|
if (explicitClaim) {
|
|
@@ -5277,6 +5723,54 @@ var ToonClient = class {
|
|
|
5277
5723
|
this.channelManager.setChannelSettled(channelId, nowSec);
|
|
5278
5724
|
return { channelId, ...r.txHash ? { txHash: r.txHash } : {} };
|
|
5279
5725
|
}
|
|
5726
|
+
/**
|
|
5727
|
+
* Submit a receive-side swap settlement bundle on-chain (toon-client#352).
|
|
5728
|
+
* The bundle comes from the sdk's `buildSettlementTx` over persisted,
|
|
5729
|
+
* verified chain-B claims (`buildSwapSettlements`); this signs it with the
|
|
5730
|
+
* client's EVM account (the claim recipient) and broadcasts it.
|
|
5731
|
+
*
|
|
5732
|
+
* Env-gated seam: EVM only, and only when `chainRpcUrls[bundle.chain]` is
|
|
5733
|
+
* configured — otherwise this throws a clear config error and callers
|
|
5734
|
+
* surface a built-not-submitted result. Solana submission and the Mina
|
|
5735
|
+
* receive-side co-sign path are explicit follow-ups (see
|
|
5736
|
+
* swap/settle-received-claims.ts module doc).
|
|
5737
|
+
*/
|
|
5738
|
+
async settleSwapBundle(bundle) {
|
|
5739
|
+
if (bundle.chainKind === "mina") {
|
|
5740
|
+
if (!this.minaPrivateKey) {
|
|
5741
|
+
throw new Error(
|
|
5742
|
+
"Mina signer not configured (no mnemonic / mina-signer) \u2014 cannot co-sign the receive-side claim."
|
|
5743
|
+
);
|
|
5744
|
+
}
|
|
5745
|
+
const makerSignature = parseMakerMinaSignature(
|
|
5746
|
+
this.config.swapMinaMakerSignatures?.[bundle.channelId]
|
|
5747
|
+
);
|
|
5748
|
+
const { txHash } = await submitMinaSettlement(bundle, {
|
|
5749
|
+
recipientPrivateKey: this.minaPrivateKey,
|
|
5750
|
+
...this.config.minaChannel?.graphqlUrl ? { graphqlUrl: this.config.minaChannel.graphqlUrl } : {},
|
|
5751
|
+
...makerSignature ? { makerSignature } : {}
|
|
5752
|
+
});
|
|
5753
|
+
return { txHash };
|
|
5754
|
+
}
|
|
5755
|
+
if (bundle.chainKind !== "evm") {
|
|
5756
|
+
throw new Error(
|
|
5757
|
+
`Swap settlement submission for ${bundle.chainKind} (${bundle.chain}) is not wired yet \u2014 EVM only today.`
|
|
5758
|
+
);
|
|
5759
|
+
}
|
|
5760
|
+
const rpcUrl = this.config.chainRpcUrls?.[bundle.chain];
|
|
5761
|
+
if (!rpcUrl) {
|
|
5762
|
+
throw new Error(
|
|
5763
|
+
`No RPC URL configured for chain "${bundle.chain}" \u2014 add it to chainRpcUrls to enable swap settlement submission.`
|
|
5764
|
+
);
|
|
5765
|
+
}
|
|
5766
|
+
if (!this.evmSigner) {
|
|
5767
|
+
throw new Error("EVM signer not configured (no evmPrivateKey/mnemonic).");
|
|
5768
|
+
}
|
|
5769
|
+
return submitEvmSettlement(bundle, {
|
|
5770
|
+
rpcUrl,
|
|
5771
|
+
account: this.evmSigner.account
|
|
5772
|
+
});
|
|
5773
|
+
}
|
|
5280
5774
|
/** Where a tracked channel sits in the withdraw journey. */
|
|
5281
5775
|
getChannelCloseState(channelId) {
|
|
5282
5776
|
if (!this.channelManager) throw new Error("ChannelManager not initialized");
|
|
@@ -5875,6 +6369,328 @@ var HttpConnectorAdmin = class {
|
|
|
5875
6369
|
}
|
|
5876
6370
|
};
|
|
5877
6371
|
|
|
6372
|
+
// src/channel/ReceivedClaimStore.ts
|
|
6373
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync } from "fs";
|
|
6374
|
+
import { dirname } from "path";
|
|
6375
|
+
function key(chain, channelId) {
|
|
6376
|
+
return `${chain}|${channelId}`;
|
|
6377
|
+
}
|
|
6378
|
+
var JsonFileReceivedClaimStore = class {
|
|
6379
|
+
filePath;
|
|
6380
|
+
constructor(filePath) {
|
|
6381
|
+
this.filePath = filePath;
|
|
6382
|
+
}
|
|
6383
|
+
save(entry) {
|
|
6384
|
+
const data = this.readFile();
|
|
6385
|
+
data[key(entry.chain, entry.channelId)] = {
|
|
6386
|
+
chain: entry.chain,
|
|
6387
|
+
channelId: entry.channelId,
|
|
6388
|
+
nonce: entry.nonce.toString(),
|
|
6389
|
+
cumulativeAmount: entry.cumulativeAmount.toString(),
|
|
6390
|
+
recipient: entry.recipient,
|
|
6391
|
+
swapSignerAddress: entry.swapSignerAddress,
|
|
6392
|
+
claimBytes: Buffer.from(entry.claimBytes).toString("base64"),
|
|
6393
|
+
...entry.claimId !== void 0 ? { claimId: entry.claimId } : {},
|
|
6394
|
+
pair: entry.pair,
|
|
6395
|
+
receivedAt: entry.receivedAt,
|
|
6396
|
+
updatedAt: entry.updatedAt,
|
|
6397
|
+
...entry.settledAt !== void 0 ? { settledAt: entry.settledAt } : {},
|
|
6398
|
+
...entry.settledNonce !== void 0 ? { settledNonce: entry.settledNonce.toString() } : {},
|
|
6399
|
+
...entry.settleTxHash !== void 0 ? { settleTxHash: entry.settleTxHash } : {}
|
|
6400
|
+
};
|
|
6401
|
+
this.writeFile(data);
|
|
6402
|
+
}
|
|
6403
|
+
load(chain, channelId) {
|
|
6404
|
+
const entry = this.readFile()[key(chain, channelId)];
|
|
6405
|
+
return entry ? fromJson(entry) : void 0;
|
|
6406
|
+
}
|
|
6407
|
+
list() {
|
|
6408
|
+
return Object.values(this.readFile()).map(fromJson);
|
|
6409
|
+
}
|
|
6410
|
+
delete(chain, channelId) {
|
|
6411
|
+
const data = this.readFile();
|
|
6412
|
+
const { [key(chain, channelId)]: _, ...rest } = data;
|
|
6413
|
+
this.writeFile(rest);
|
|
6414
|
+
}
|
|
6415
|
+
readFile() {
|
|
6416
|
+
if (!existsSync2(this.filePath)) {
|
|
6417
|
+
return {};
|
|
6418
|
+
}
|
|
6419
|
+
const raw = readFileSync2(this.filePath, "utf-8");
|
|
6420
|
+
return JSON.parse(raw);
|
|
6421
|
+
}
|
|
6422
|
+
writeFile(data) {
|
|
6423
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
6424
|
+
writeFileSync2(this.filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
6425
|
+
}
|
|
6426
|
+
};
|
|
6427
|
+
var InMemoryReceivedClaimStore = class {
|
|
6428
|
+
entries = /* @__PURE__ */ new Map();
|
|
6429
|
+
save(entry) {
|
|
6430
|
+
this.entries.set(key(entry.chain, entry.channelId), { ...entry });
|
|
6431
|
+
}
|
|
6432
|
+
load(chain, channelId) {
|
|
6433
|
+
const entry = this.entries.get(key(chain, channelId));
|
|
6434
|
+
return entry ? { ...entry } : void 0;
|
|
6435
|
+
}
|
|
6436
|
+
list() {
|
|
6437
|
+
return [...this.entries.values()].map((e) => ({ ...e }));
|
|
6438
|
+
}
|
|
6439
|
+
delete(chain, channelId) {
|
|
6440
|
+
this.entries.delete(key(chain, channelId));
|
|
6441
|
+
}
|
|
6442
|
+
};
|
|
6443
|
+
function fromJson(entry) {
|
|
6444
|
+
return {
|
|
6445
|
+
chain: entry.chain,
|
|
6446
|
+
channelId: entry.channelId,
|
|
6447
|
+
nonce: BigInt(entry.nonce),
|
|
6448
|
+
cumulativeAmount: BigInt(entry.cumulativeAmount),
|
|
6449
|
+
recipient: entry.recipient,
|
|
6450
|
+
swapSignerAddress: entry.swapSignerAddress,
|
|
6451
|
+
claimBytes: new Uint8Array(Buffer.from(entry.claimBytes, "base64")),
|
|
6452
|
+
...entry.claimId !== void 0 ? { claimId: entry.claimId } : {},
|
|
6453
|
+
pair: entry.pair,
|
|
6454
|
+
receivedAt: entry.receivedAt,
|
|
6455
|
+
updatedAt: entry.updatedAt,
|
|
6456
|
+
...entry.settledAt !== void 0 ? { settledAt: entry.settledAt } : {},
|
|
6457
|
+
...entry.settledNonce !== void 0 ? { settledNonce: BigInt(entry.settledNonce) } : {},
|
|
6458
|
+
...entry.settleTxHash !== void 0 ? { settleTxHash: entry.settleTxHash } : {}
|
|
6459
|
+
};
|
|
6460
|
+
}
|
|
6461
|
+
|
|
6462
|
+
// src/swap/received-claims.ts
|
|
6463
|
+
import {
|
|
6464
|
+
verifyAccumulatedClaim
|
|
6465
|
+
} from "@toon-protocol/sdk";
|
|
6466
|
+
function hasSettlementMetadata(claim) {
|
|
6467
|
+
return claim.channelId !== void 0 && claim.nonce !== void 0 && claim.cumulativeAmount !== void 0 && claim.recipient !== void 0 && claim.swapSignerAddress !== void 0;
|
|
6468
|
+
}
|
|
6469
|
+
function sameAddress(chain, a, b) {
|
|
6470
|
+
return chain.startsWith("evm") ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
6471
|
+
}
|
|
6472
|
+
function signatureRejectionCode(reason) {
|
|
6473
|
+
if (reason.startsWith("SIGNER_MISMATCH")) return "SIGNER_MISMATCH";
|
|
6474
|
+
if (reason.startsWith("MINA_VERIFICATION_UNSUPPORTED"))
|
|
6475
|
+
return "MINA_VERIFICATION_UNSUPPORTED";
|
|
6476
|
+
if (reason.startsWith("UNSUPPORTED_CHAIN")) return "UNSUPPORTED_CHAIN";
|
|
6477
|
+
return "SIGNATURE_INVALID";
|
|
6478
|
+
}
|
|
6479
|
+
function ingestReceivedClaims(params) {
|
|
6480
|
+
const now = params.now ?? Date.now;
|
|
6481
|
+
const verified = [];
|
|
6482
|
+
const rejected = [];
|
|
6483
|
+
const legacy = [];
|
|
6484
|
+
let valueReceived = 0n;
|
|
6485
|
+
const watermarks = /* @__PURE__ */ new Map();
|
|
6486
|
+
const reject = (claim, code, message) => {
|
|
6487
|
+
rejected.push({ claim, code, message });
|
|
6488
|
+
};
|
|
6489
|
+
for (const claim of params.claims) {
|
|
6490
|
+
if (!hasSettlementMetadata(claim)) {
|
|
6491
|
+
legacy.push(claim);
|
|
6492
|
+
continue;
|
|
6493
|
+
}
|
|
6494
|
+
const chain = claim.pair.to.chain;
|
|
6495
|
+
if (chain !== params.expectedChain) {
|
|
6496
|
+
reject(
|
|
6497
|
+
claim,
|
|
6498
|
+
"CHAIN_MISMATCH",
|
|
6499
|
+
`claim settles on "${chain}", session expected "${params.expectedChain}"`
|
|
6500
|
+
);
|
|
6501
|
+
continue;
|
|
6502
|
+
}
|
|
6503
|
+
if (!sameAddress(chain, claim.recipient, params.chainRecipient)) {
|
|
6504
|
+
reject(
|
|
6505
|
+
claim,
|
|
6506
|
+
"RECIPIENT_MISMATCH",
|
|
6507
|
+
`claim recipient "${claim.recipient}" is not the session chainRecipient "${params.chainRecipient}"`
|
|
6508
|
+
);
|
|
6509
|
+
continue;
|
|
6510
|
+
}
|
|
6511
|
+
if (params.expectedSignerAddress !== void 0 && !sameAddress(chain, claim.swapSignerAddress, params.expectedSignerAddress)) {
|
|
6512
|
+
reject(
|
|
6513
|
+
claim,
|
|
6514
|
+
"SWAP_SIGNER_MISMATCH",
|
|
6515
|
+
`claim swapSignerAddress "${claim.swapSignerAddress}" does not match the maker's advertised signer "${params.expectedSignerAddress}"`
|
|
6516
|
+
);
|
|
6517
|
+
continue;
|
|
6518
|
+
}
|
|
6519
|
+
const expectedSigner = params.expectedSignerAddress ?? claim.swapSignerAddress;
|
|
6520
|
+
const sig = verifyAccumulatedClaim(
|
|
6521
|
+
claim,
|
|
6522
|
+
{ address: expectedSigner },
|
|
6523
|
+
params.minaSignerClient
|
|
6524
|
+
);
|
|
6525
|
+
if (!sig.valid) {
|
|
6526
|
+
reject(claim, signatureRejectionCode(sig.reason), sig.reason);
|
|
6527
|
+
continue;
|
|
6528
|
+
}
|
|
6529
|
+
let nonce;
|
|
6530
|
+
let cumulativeAmount;
|
|
6531
|
+
try {
|
|
6532
|
+
nonce = BigInt(claim.nonce);
|
|
6533
|
+
cumulativeAmount = BigInt(claim.cumulativeAmount);
|
|
6534
|
+
} catch {
|
|
6535
|
+
reject(
|
|
6536
|
+
claim,
|
|
6537
|
+
"MALFORMED_METADATA",
|
|
6538
|
+
`nonce "${claim.nonce}" / cumulativeAmount "${claim.cumulativeAmount}" are not decimal integers`
|
|
6539
|
+
);
|
|
6540
|
+
continue;
|
|
6541
|
+
}
|
|
6542
|
+
const wmKey = `${chain}|${claim.channelId}`;
|
|
6543
|
+
const watermark = watermarks.get(wmKey) ?? params.store.load(chain, claim.channelId);
|
|
6544
|
+
if (watermark) {
|
|
6545
|
+
if (!sameAddress(chain, watermark.swapSignerAddress, expectedSigner)) {
|
|
6546
|
+
reject(
|
|
6547
|
+
claim,
|
|
6548
|
+
"SWAP_SIGNER_MISMATCH",
|
|
6549
|
+
`channel ${claim.channelId} watermark was signed by "${watermark.swapSignerAddress}"; a claim signed by "${expectedSigner}" may not rotate it`
|
|
6550
|
+
);
|
|
6551
|
+
continue;
|
|
6552
|
+
}
|
|
6553
|
+
if (nonce <= watermark.nonce) {
|
|
6554
|
+
reject(
|
|
6555
|
+
claim,
|
|
6556
|
+
"NON_MONOTONIC_NONCE",
|
|
6557
|
+
`nonce ${nonce} does not advance the persisted watermark nonce ${watermark.nonce} for channel ${claim.channelId}`
|
|
6558
|
+
);
|
|
6559
|
+
continue;
|
|
6560
|
+
}
|
|
6561
|
+
if (cumulativeAmount <= watermark.cumulativeAmount) {
|
|
6562
|
+
reject(
|
|
6563
|
+
claim,
|
|
6564
|
+
"NON_MONOTONIC_CUMULATIVE",
|
|
6565
|
+
`cumulativeAmount ${cumulativeAmount} does not advance the persisted watermark ${watermark.cumulativeAmount} for channel ${claim.channelId}`
|
|
6566
|
+
);
|
|
6567
|
+
continue;
|
|
6568
|
+
}
|
|
6569
|
+
}
|
|
6570
|
+
const advance = cumulativeAmount - (watermark?.cumulativeAmount ?? 0n);
|
|
6571
|
+
if (advance < claim.targetAmount) {
|
|
6572
|
+
reject(
|
|
6573
|
+
claim,
|
|
6574
|
+
"CUMULATIVE_SHORTFALL",
|
|
6575
|
+
`cumulative advance ${advance} is less than the packet's targetAmount ${claim.targetAmount} for channel ${claim.channelId}`
|
|
6576
|
+
);
|
|
6577
|
+
continue;
|
|
6578
|
+
}
|
|
6579
|
+
const entry = {
|
|
6580
|
+
chain,
|
|
6581
|
+
channelId: claim.channelId,
|
|
6582
|
+
nonce,
|
|
6583
|
+
cumulativeAmount,
|
|
6584
|
+
recipient: claim.recipient,
|
|
6585
|
+
swapSignerAddress: expectedSigner,
|
|
6586
|
+
claimBytes: claim.claimBytes,
|
|
6587
|
+
...claim.claimId !== void 0 ? { claimId: claim.claimId } : {},
|
|
6588
|
+
pair: claim.pair,
|
|
6589
|
+
receivedAt: claim.receivedAt,
|
|
6590
|
+
updatedAt: now(),
|
|
6591
|
+
// Settlement bookkeeping survives watermark advances.
|
|
6592
|
+
...watermark?.settledAt !== void 0 ? { settledAt: watermark.settledAt } : {},
|
|
6593
|
+
...watermark?.settledNonce !== void 0 ? { settledNonce: watermark.settledNonce } : {},
|
|
6594
|
+
...watermark?.settleTxHash !== void 0 ? { settleTxHash: watermark.settleTxHash } : {}
|
|
6595
|
+
};
|
|
6596
|
+
params.store.save(entry);
|
|
6597
|
+
watermarks.set(wmKey, entry);
|
|
6598
|
+
verified.push({ claim, watermarkAdvance: advance });
|
|
6599
|
+
valueReceived += advance;
|
|
6600
|
+
}
|
|
6601
|
+
return { verified, rejected, legacy, valueReceived };
|
|
6602
|
+
}
|
|
6603
|
+
|
|
6604
|
+
// src/swap/preimage-retention.ts
|
|
6605
|
+
function copy(entry) {
|
|
6606
|
+
return {
|
|
6607
|
+
packetIndex: entry.packetIndex,
|
|
6608
|
+
preimage: Uint8Array.from(entry.preimage),
|
|
6609
|
+
condition: Uint8Array.from(entry.condition),
|
|
6610
|
+
retainedAt: entry.retainedAt
|
|
6611
|
+
};
|
|
6612
|
+
}
|
|
6613
|
+
var InMemoryPreimageRetentionStore = class {
|
|
6614
|
+
entries = /* @__PURE__ */ new Map();
|
|
6615
|
+
retain(entry) {
|
|
6616
|
+
this.entries.set(entry.packetIndex, copy(entry));
|
|
6617
|
+
}
|
|
6618
|
+
get(packetIndex) {
|
|
6619
|
+
const entry = this.entries.get(packetIndex);
|
|
6620
|
+
return entry ? copy(entry) : void 0;
|
|
6621
|
+
}
|
|
6622
|
+
take(packetIndex) {
|
|
6623
|
+
const entry = this.entries.get(packetIndex);
|
|
6624
|
+
if (!entry) return void 0;
|
|
6625
|
+
this.entries.delete(packetIndex);
|
|
6626
|
+
return copy(entry);
|
|
6627
|
+
}
|
|
6628
|
+
size() {
|
|
6629
|
+
return this.entries.size;
|
|
6630
|
+
}
|
|
6631
|
+
clear() {
|
|
6632
|
+
this.entries.clear();
|
|
6633
|
+
}
|
|
6634
|
+
};
|
|
6635
|
+
|
|
6636
|
+
// src/swap/atomic-reveal.ts
|
|
6637
|
+
function rollbackWatermark(store, chain, channelId, prior) {
|
|
6638
|
+
if (prior === void 0) {
|
|
6639
|
+
store.delete(chain, channelId);
|
|
6640
|
+
} else {
|
|
6641
|
+
store.save(prior);
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
async function ingestAndReveal(params) {
|
|
6645
|
+
const { reveal, preimages, claims, store, ...shared } = params;
|
|
6646
|
+
const revealed = [];
|
|
6647
|
+
const rolledBack = [];
|
|
6648
|
+
const rejected = [];
|
|
6649
|
+
const legacy = [];
|
|
6650
|
+
let valueRevealed = 0n;
|
|
6651
|
+
for (const claim of claims) {
|
|
6652
|
+
const hasMeta = hasSettlementMetadata(claim);
|
|
6653
|
+
const chain = hasMeta ? claim.pair.to.chain : void 0;
|
|
6654
|
+
const channelId = hasMeta ? claim.channelId : void 0;
|
|
6655
|
+
const prior = chain !== void 0 && channelId !== void 0 ? store.load(chain, channelId) : void 0;
|
|
6656
|
+
const ingest = ingestReceivedClaims({ ...shared, claims: [claim], store });
|
|
6657
|
+
if (ingest.legacy.length > 0) {
|
|
6658
|
+
legacy.push(claim);
|
|
6659
|
+
continue;
|
|
6660
|
+
}
|
|
6661
|
+
const rejection = ingest.rejected[0];
|
|
6662
|
+
if (rejection) {
|
|
6663
|
+
rejected.push(rejection);
|
|
6664
|
+
continue;
|
|
6665
|
+
}
|
|
6666
|
+
const verified = ingest.verified[0];
|
|
6667
|
+
if (!verified || chain === void 0 || channelId === void 0) continue;
|
|
6668
|
+
const advance = verified.watermarkAdvance;
|
|
6669
|
+
const preimage = preimages?.take(claim.packetIndex);
|
|
6670
|
+
let outcome;
|
|
6671
|
+
try {
|
|
6672
|
+
outcome = await reveal(claim, preimage);
|
|
6673
|
+
} catch (err) {
|
|
6674
|
+
outcome = {
|
|
6675
|
+
decision: "withheld",
|
|
6676
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
6677
|
+
};
|
|
6678
|
+
}
|
|
6679
|
+
if (outcome.decision === "revealed") {
|
|
6680
|
+
revealed.push({ claim, watermarkAdvance: advance });
|
|
6681
|
+
valueRevealed += advance;
|
|
6682
|
+
continue;
|
|
6683
|
+
}
|
|
6684
|
+
rollbackWatermark(store, chain, channelId, prior);
|
|
6685
|
+
rolledBack.push({
|
|
6686
|
+
claim,
|
|
6687
|
+
watermarkAdvance: advance,
|
|
6688
|
+
reason: outcome.reason ?? "reveal withheld"
|
|
6689
|
+
});
|
|
6690
|
+
}
|
|
6691
|
+
return { revealed, rolledBack, rejected, legacy, valueRevealed };
|
|
6692
|
+
}
|
|
6693
|
+
|
|
5878
6694
|
// src/faucet.ts
|
|
5879
6695
|
function defaultFaucetTimeout(chain) {
|
|
5880
6696
|
return chain === "mina" ? 12e4 : 3e4;
|
|
@@ -6854,7 +7670,7 @@ import {
|
|
|
6854
7670
|
createDecipheriv,
|
|
6855
7671
|
randomBytes as randomBytes2
|
|
6856
7672
|
} from "crypto";
|
|
6857
|
-
import { writeFileSync as
|
|
7673
|
+
import { writeFileSync as writeFileSync3, readFileSync as readFileSync3 } from "fs";
|
|
6858
7674
|
var SCRYPT_N = 2 ** 17;
|
|
6859
7675
|
var SCRYPT_R = 8;
|
|
6860
7676
|
var SCRYPT_P = 1;
|
|
@@ -6881,14 +7697,14 @@ function encryptMnemonic2(mnemonic, password) {
|
|
|
6881
7697
|
}
|
|
6882
7698
|
const salt = randomBytes2(SALT_LEN);
|
|
6883
7699
|
const iv = randomBytes2(IV_LEN);
|
|
6884
|
-
const
|
|
7700
|
+
const key2 = scryptSync(password, salt, SCRYPT_KEY_LEN, {
|
|
6885
7701
|
N: SCRYPT_N,
|
|
6886
7702
|
r: SCRYPT_R,
|
|
6887
7703
|
p: SCRYPT_P,
|
|
6888
7704
|
maxmem: SCRYPT_MAXMEM
|
|
6889
7705
|
});
|
|
6890
7706
|
try {
|
|
6891
|
-
const cipher = createCipheriv("aes-256-gcm",
|
|
7707
|
+
const cipher = createCipheriv("aes-256-gcm", key2, iv, {
|
|
6892
7708
|
authTagLength: AUTH_TAG_LEN
|
|
6893
7709
|
});
|
|
6894
7710
|
const ciphertext = Buffer.concat([
|
|
@@ -6904,7 +7720,7 @@ function encryptMnemonic2(mnemonic, password) {
|
|
|
6904
7720
|
version: 1
|
|
6905
7721
|
};
|
|
6906
7722
|
} finally {
|
|
6907
|
-
|
|
7723
|
+
key2.fill(0);
|
|
6908
7724
|
}
|
|
6909
7725
|
}
|
|
6910
7726
|
function decryptMnemonic2(encrypted, password) {
|
|
@@ -6919,14 +7735,14 @@ function decryptMnemonic2(encrypted, password) {
|
|
|
6919
7735
|
const iv = Buffer.from(encrypted.iv, "base64");
|
|
6920
7736
|
const ciphertext = Buffer.from(encrypted.ciphertext, "base64");
|
|
6921
7737
|
const tag = Buffer.from(encrypted.tag, "base64");
|
|
6922
|
-
const
|
|
7738
|
+
const key2 = scryptSync(password, salt, SCRYPT_KEY_LEN, {
|
|
6923
7739
|
N: SCRYPT_N,
|
|
6924
7740
|
r: SCRYPT_R,
|
|
6925
7741
|
p: SCRYPT_P,
|
|
6926
7742
|
maxmem: SCRYPT_MAXMEM
|
|
6927
7743
|
});
|
|
6928
7744
|
try {
|
|
6929
|
-
const decipher = createDecipheriv("aes-256-gcm",
|
|
7745
|
+
const decipher = createDecipheriv("aes-256-gcm", key2, iv, {
|
|
6930
7746
|
authTagLength: AUTH_TAG_LEN
|
|
6931
7747
|
});
|
|
6932
7748
|
decipher.setAuthTag(tag);
|
|
@@ -6942,7 +7758,7 @@ function decryptMnemonic2(encrypted, password) {
|
|
|
6942
7758
|
);
|
|
6943
7759
|
}
|
|
6944
7760
|
} finally {
|
|
6945
|
-
|
|
7761
|
+
key2.fill(0);
|
|
6946
7762
|
}
|
|
6947
7763
|
}
|
|
6948
7764
|
function generateKeystore(path, password) {
|
|
@@ -6965,7 +7781,7 @@ function importKeystore(path, mnemonic, password) {
|
|
|
6965
7781
|
}
|
|
6966
7782
|
function loadKeystore(path, password) {
|
|
6967
7783
|
assertNode();
|
|
6968
|
-
const raw =
|
|
7784
|
+
const raw = readFileSync3(path, "utf8");
|
|
6969
7785
|
let parsed;
|
|
6970
7786
|
try {
|
|
6971
7787
|
parsed = JSON.parse(raw);
|
|
@@ -6976,7 +7792,7 @@ function loadKeystore(path, password) {
|
|
|
6976
7792
|
}
|
|
6977
7793
|
function writeKeystoreFile(path, keystore) {
|
|
6978
7794
|
assertNode();
|
|
6979
|
-
|
|
7795
|
+
writeFileSync3(path, JSON.stringify(keystore, null, 2), {
|
|
6980
7796
|
encoding: "utf8",
|
|
6981
7797
|
mode: 384
|
|
6982
7798
|
});
|
|
@@ -6998,10 +7814,15 @@ export {
|
|
|
6998
7814
|
ILP_CLAIM_HEADER,
|
|
6999
7815
|
ILP_CLAIM_WRAPPED_HEADER,
|
|
7000
7816
|
ILP_PEER_ID_HEADER,
|
|
7817
|
+
InMemoryPreimageRetentionStore,
|
|
7818
|
+
InMemoryReceivedClaimStore,
|
|
7819
|
+
JsonFileReceivedClaimStore,
|
|
7001
7820
|
KeyManager,
|
|
7002
7821
|
KindRegistry,
|
|
7003
7822
|
MIME_A2UI,
|
|
7004
7823
|
MIME_MCP_APP,
|
|
7824
|
+
MINA_CHANNEL_STATE,
|
|
7825
|
+
MinaSettlementError,
|
|
7005
7826
|
MinaSigner,
|
|
7006
7827
|
NetworkError,
|
|
7007
7828
|
OnChainChannelClient,
|
|
@@ -7018,11 +7839,15 @@ export {
|
|
|
7018
7839
|
buildBackupEvent,
|
|
7019
7840
|
buildBackupFilter,
|
|
7020
7841
|
buildConsentRequest,
|
|
7842
|
+
buildMinaCoSignedClaim,
|
|
7021
7843
|
buildRendererEventTemplate,
|
|
7022
7844
|
buildSettlementInfo,
|
|
7023
7845
|
buildStoreWriteEnvelope,
|
|
7846
|
+
buildSwapSettlements,
|
|
7024
7847
|
buildUiCoordinate,
|
|
7025
7848
|
classifyIntent,
|
|
7849
|
+
createO1jsMinaClaimSubmitter,
|
|
7850
|
+
decodeEvmSettlementTx,
|
|
7026
7851
|
decryptMnemonic2 as decryptMnemonic,
|
|
7027
7852
|
defaultFaucetTimeout,
|
|
7028
7853
|
deriveFromNsec,
|
|
@@ -7030,6 +7855,7 @@ export {
|
|
|
7030
7855
|
deriveNostrKeyFromMnemonic,
|
|
7031
7856
|
deterministicGenerator,
|
|
7032
7857
|
encryptMnemonic2 as encryptMnemonic,
|
|
7858
|
+
entryToAccumulatedClaim,
|
|
7033
7859
|
extractArweaveTxId,
|
|
7034
7860
|
extractUiResource,
|
|
7035
7861
|
fulfillmentMatchesCondition,
|
|
@@ -7040,8 +7866,11 @@ export {
|
|
|
7040
7866
|
getNetworkStatus,
|
|
7041
7867
|
getUiCoordinate,
|
|
7042
7868
|
guardedRenderDispatch,
|
|
7869
|
+
hasSettlementMetadata,
|
|
7043
7870
|
httpEndpointToBtpUrl,
|
|
7044
7871
|
importKeystore,
|
|
7872
|
+
ingestAndReveal,
|
|
7873
|
+
ingestReceivedClaims,
|
|
7045
7874
|
isInsufficientGasError,
|
|
7046
7875
|
isPrfSupported,
|
|
7047
7876
|
isTrustDowngrade,
|
|
@@ -7049,6 +7878,7 @@ export {
|
|
|
7049
7878
|
loadKeystore,
|
|
7050
7879
|
mintExecutionCondition,
|
|
7051
7880
|
parseBackupPayload,
|
|
7881
|
+
parseEvmChainId2 as parseEvmChainId,
|
|
7052
7882
|
parseFulfillHttp,
|
|
7053
7883
|
parseFulfillHttpBytes,
|
|
7054
7884
|
parseHttpResponse,
|
|
@@ -7061,6 +7891,7 @@ export {
|
|
|
7061
7891
|
readEvmNativeBalance,
|
|
7062
7892
|
readEvmTokenBalance,
|
|
7063
7893
|
readMinaBalance,
|
|
7894
|
+
readMinaChannelState,
|
|
7064
7895
|
readMinaDepositTotal,
|
|
7065
7896
|
readSolanaNativeBalance,
|
|
7066
7897
|
readSolanaTokenBalance,
|
|
@@ -7074,6 +7905,8 @@ export {
|
|
|
7074
7905
|
selectIlpTransport,
|
|
7075
7906
|
selectLatestAddressable,
|
|
7076
7907
|
serializeHttpRequest,
|
|
7908
|
+
submitEvmSettlement,
|
|
7909
|
+
submitMinaSettlement,
|
|
7077
7910
|
validateConfig,
|
|
7078
7911
|
validateMnemonic,
|
|
7079
7912
|
verifyRendererTrust,
|