@toon-protocol/client 0.20.2 → 0.21.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/dist/index.js CHANGED
@@ -25,6 +25,11 @@ import {
25
25
  selectLatestAddressable,
26
26
  verifyRendererTrust
27
27
  } from "./chunk-QEMD5EAI.js";
28
+ import {
29
+ deployMinaChannelZkApp,
30
+ ensureOwnedMinaZkApp,
31
+ openMinaChannelOnChain
32
+ } from "./chunk-OM3MHJHC.js";
28
33
 
29
34
  // src/ToonClient.ts
30
35
  import { generateSecretKey as generateSecretKey3, getPublicKey as getPublicKey2, finalizeEvent } from "nostr-tools/pure";
@@ -2186,181 +2191,6 @@ async function depositSolanaChannel(params) {
2186
2191
  return { depositTxSignature };
2187
2192
  }
2188
2193
 
2189
- // src/channel/mina-channel-open.ts
2190
- import { hexToMinaBase58PrivateKey as hexToMinaBase58PrivateKey2 } from "@toon-protocol/core";
2191
- var cachedO1js = null;
2192
- var cachedPaymentChannel = null;
2193
- var compiledContract = null;
2194
- var runtimeOverride = null;
2195
- async function loadMinaRuntime() {
2196
- if (cachedO1js && cachedPaymentChannel) {
2197
- return { o1js: cachedO1js, PaymentChannel: cachedPaymentChannel };
2198
- }
2199
- if (runtimeOverride) {
2200
- const injected = await runtimeOverride();
2201
- cachedO1js = injected.o1js;
2202
- cachedPaymentChannel = injected.PaymentChannel;
2203
- return injected;
2204
- }
2205
- const { createRequire } = await import("module");
2206
- const nodePath = await import("path");
2207
- const requireHere = createRequire(import.meta.url);
2208
- const mzkPkgPath = requireHere.resolve(
2209
- "@toon-protocol/mina-zkapp/package.json"
2210
- );
2211
- const requireFromMzk = createRequire(mzkPkgPath);
2212
- const o1js = requireFromMzk("o1js");
2213
- const mzkPkgJson = requireFromMzk(mzkPkgPath);
2214
- const mzkDir = nodePath.dirname(mzkPkgPath);
2215
- const mzkEntry = nodePath.join(mzkDir, mzkPkgJson.main ?? "dist/index.js");
2216
- const mzk = requireFromMzk(mzkEntry);
2217
- const PaymentChannel = mzk.PaymentChannel ?? mzk.default?.PaymentChannel;
2218
- if (!PaymentChannel) {
2219
- throw new Error(
2220
- "@toon-protocol/mina-zkapp does not export PaymentChannel \u2014 cannot open a Mina channel"
2221
- );
2222
- }
2223
- cachedO1js = o1js;
2224
- cachedPaymentChannel = PaymentChannel;
2225
- return { o1js, PaymentChannel };
2226
- }
2227
- async function getO1js() {
2228
- return (await loadMinaRuntime()).o1js;
2229
- }
2230
- async function getCompiledPaymentChannel() {
2231
- const { PaymentChannel } = await loadMinaRuntime();
2232
- if (!compiledContract) {
2233
- await PaymentChannel.compile();
2234
- compiledContract = PaymentChannel;
2235
- }
2236
- return compiledContract;
2237
- }
2238
- var MINA_CHANNEL_STATE_OPEN = 1n;
2239
- var MINA_CHANNEL_STATE_UNINITIALIZED = 0n;
2240
- async function openMinaChannelOnChain(params) {
2241
- const { Mina, PrivateKey, PublicKey, Field, AccountUpdate, fetchAccount } = await getO1js();
2242
- const network = Mina.Network(params.graphqlUrl);
2243
- Mina.setActiveInstance(network);
2244
- const txFee = params.feeNanomina ?? 100000000n;
2245
- const payerKeyBase58 = hexToMinaBase58PrivateKey2(params.payerPrivateKey);
2246
- const payerPrivateKey = PrivateKey.fromBase58(payerKeyBase58);
2247
- const payerPublicKey = payerPrivateKey.toPublicKey();
2248
- const zkAppPublicKey = PublicKey.fromBase58(params.zkAppAddress);
2249
- const readChannelState = async () => {
2250
- const res = await fetchAccount({ publicKey: zkAppPublicKey });
2251
- if (res.error || !res.account) {
2252
- throw new Error(
2253
- `Mina zkApp account ${params.zkAppAddress} not found on-chain (${String(
2254
- res.error
2255
- )}) \u2014 deploy the PaymentChannel zkApp before opening a channel`
2256
- );
2257
- }
2258
- const appState = res.account.zkapp?.appState;
2259
- const raw = appState?.[3]?.toString() ?? "0";
2260
- return BigInt(raw);
2261
- };
2262
- const readDepositTotal = async () => {
2263
- const res = await fetchAccount({ publicKey: zkAppPublicKey });
2264
- if (res.error || !res.account) {
2265
- throw new Error(
2266
- `Mina zkApp account ${params.zkAppAddress} not found on-chain (${String(
2267
- res.error
2268
- )}) \u2014 deploy the PaymentChannel zkApp before opening a channel`
2269
- );
2270
- }
2271
- const appState = res.account.zkapp?.appState;
2272
- const raw = appState?.[4]?.toString() ?? "0";
2273
- return BigInt(raw);
2274
- };
2275
- const currentState = await readChannelState();
2276
- await fetchAccount({ publicKey: payerPublicKey });
2277
- let opened = false;
2278
- let initTxHash;
2279
- let zkApp;
2280
- const getZkApp = async () => {
2281
- if (!zkApp) {
2282
- const PaymentChannel = await getCompiledPaymentChannel();
2283
- zkApp = new PaymentChannel(zkAppPublicKey);
2284
- }
2285
- return zkApp;
2286
- };
2287
- if (currentState === MINA_CHANNEL_STATE_UNINITIALIZED) {
2288
- const channel = await getZkApp();
2289
- const participantA = payerPublicKey;
2290
- const participantB = params.peerPublicKey ? PublicKey.fromBase58(params.peerPublicKey) : payerPublicKey;
2291
- const nonce = Field(0);
2292
- const timeoutField = Field((params.timeout ?? 86400n).toString());
2293
- const tokenIdField = Field(params.tokenId ?? "1");
2294
- await fetchAccount({ publicKey: zkAppPublicKey });
2295
- await fetchAccount({ publicKey: payerPublicKey });
2296
- const initTx = await Mina.transaction(
2297
- { sender: payerPublicKey, fee: Number(txFee) },
2298
- async () => {
2299
- await channel.initializeChannel(
2300
- participantA,
2301
- participantB,
2302
- nonce,
2303
- timeoutField,
2304
- tokenIdField
2305
- );
2306
- }
2307
- );
2308
- await initTx.prove();
2309
- const sentInit = await initTx.sign([payerPrivateKey]).send();
2310
- initTxHash = sentInit.hash ?? void 0;
2311
- opened = true;
2312
- await sentInit.wait();
2313
- await fetchAccount({ publicKey: zkAppPublicKey });
2314
- await fetchAccount({ publicKey: payerPublicKey });
2315
- } else if (currentState !== MINA_CHANNEL_STATE_OPEN) {
2316
- throw new Error(
2317
- `Mina channel ${params.zkAppAddress} is in state ${currentState} (not UNINITIALIZED/OPEN) \u2014 cannot open`
2318
- );
2319
- }
2320
- let depositTxHash;
2321
- if (params.deposit && params.deposit.amount > 0n) {
2322
- const channel = await getZkApp();
2323
- await fetchAccount({ publicKey: zkAppPublicKey });
2324
- const amountField = Field(params.deposit.amount.toString());
2325
- const depositTx = await Mina.transaction(
2326
- { sender: payerPublicKey, fee: Number(txFee) },
2327
- async () => {
2328
- await channel.deposit(amountField, payerPublicKey);
2329
- }
2330
- );
2331
- await depositTx.prove();
2332
- const sentDeposit = await depositTx.sign([payerPrivateKey]).send();
2333
- depositTxHash = sentDeposit.hash ?? void 0;
2334
- await sentDeposit.wait();
2335
- await fetchAccount({ publicKey: zkAppPublicKey });
2336
- await fetchAccount({ publicKey: payerPublicKey });
2337
- }
2338
- let finalState;
2339
- try {
2340
- finalState = Number(await readChannelState());
2341
- } catch {
2342
- finalState = opened ? Number(MINA_CHANNEL_STATE_OPEN) : Number(currentState);
2343
- }
2344
- if (opened && finalState === Number(MINA_CHANNEL_STATE_UNINITIALIZED)) {
2345
- finalState = Number(MINA_CHANNEL_STATE_OPEN);
2346
- }
2347
- void AccountUpdate;
2348
- let depositTotal;
2349
- try {
2350
- depositTotal = await readDepositTotal();
2351
- } catch {
2352
- depositTotal = 0n;
2353
- }
2354
- return {
2355
- zkAppAddress: params.zkAppAddress,
2356
- opened,
2357
- initTxHash,
2358
- depositTxHash,
2359
- channelState: finalState,
2360
- depositTotal
2361
- };
2362
- }
2363
-
2364
2194
  // src/channel/OnChainChannelClient.ts
2365
2195
  var TOKEN_NETWORK_ABI = [
2366
2196
  {
@@ -2870,15 +2700,28 @@ var OnChainChannelClient = class {
2870
2700
  "Mina channel config not provided \u2014 cannot open Mina channel"
2871
2701
  );
2872
2702
  }
2873
- const zkAppAddress = this.minaConfig.zkAppAddress;
2874
- if (!zkAppAddress) {
2703
+ if (!params.peerAddress) {
2875
2704
  throw new Error(
2876
- "Mina channel requires a deployed zkAppAddress (minaConfig.zkAppAddress)"
2705
+ "Mina channel requires peerAddress (apex Mina settlement B62) so the on-chain channel is opened two-party \u2014 the participant-form claim cannot settle against a single-party channel"
2877
2706
  );
2878
2707
  }
2879
- if (!params.peerAddress) {
2708
+ let zkAppAddress = this.minaConfig.zkAppAddress;
2709
+ if (this.minaConfig.autoDeploy) {
2710
+ const { ensureOwnedMinaZkApp: ensureOwnedMinaZkApp2 } = await import("./mina-channel-deploy-CO2LMPPB.js");
2711
+ const ensured = await ensureOwnedMinaZkApp2({
2712
+ graphqlUrl: this.minaConfig.graphqlUrl,
2713
+ payerPrivateKey: this.minaConfig.privateKey,
2714
+ peerPublicKey: params.peerAddress,
2715
+ ...this.minaConfig.autoDeploy.deployed ? { deployed: this.minaConfig.autoDeploy.deployed } : {},
2716
+ ...zkAppAddress ? { candidateZkAppAddress: zkAppAddress } : {},
2717
+ ...this.minaConfig.autoDeploy.onDeployed ? { onDeployed: this.minaConfig.autoDeploy.onDeployed } : {},
2718
+ ...this.minaConfig.autoDeploy.onProgress ? { onProgress: this.minaConfig.autoDeploy.onProgress } : {}
2719
+ });
2720
+ zkAppAddress = ensured.zkAppAddress;
2721
+ }
2722
+ if (!zkAppAddress) {
2880
2723
  throw new Error(
2881
- "Mina channel requires peerAddress (apex Mina settlement B62) so the on-chain channel is opened two-party \u2014 the participant-form claim cannot settle against a single-party channel"
2724
+ "Mina channel requires a deployed zkAppAddress (minaConfig.zkAppAddress)"
2882
2725
  );
2883
2726
  }
2884
2727
  const timeout = BigInt(
@@ -3327,7 +3170,7 @@ var SolanaSigner = class {
3327
3170
  };
3328
3171
 
3329
3172
  // src/signing/mina-signer.ts
3330
- import { hexToMinaBase58PrivateKey as hexToMinaBase58PrivateKey3 } from "@toon-protocol/core";
3173
+ import { hexToMinaBase58PrivateKey as hexToMinaBase58PrivateKey2 } from "@toon-protocol/core";
3331
3174
  import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
3332
3175
  import { bytesToHex } from "@noble/hashes/utils.js";
3333
3176
 
@@ -3574,7 +3417,7 @@ var MinaSigner = class {
3574
3417
  "MinaSigner requires a zkAppAddress (channel id) to sign a balance proof"
3575
3418
  );
3576
3419
  }
3577
- const minaPrivateKey = hexToMinaBase58PrivateKey3(this.privateKey);
3420
+ const minaPrivateKey = hexToMinaBase58PrivateKey2(this.privateKey);
3578
3421
  const tokenId = params.metadata.tokenId ?? DEFAULT_MINA_TOKEN_ID;
3579
3422
  const salt = deriveMinaSalt(zkAppAddress, params.nonce);
3580
3423
  const clientPubKey = this.publicKeyBase58 ?? await this.deriveOwnPublicKey(minaPrivateKey);
@@ -4059,6 +3902,7 @@ var JsonFileChannelStore = class {
4059
3902
 
4060
3903
  // src/balance/WalletBalanceReader.ts
4061
3904
  import { createPublicClient as createPublicClient2, http as http2, defineChain as defineChain2 } from "viem";
3905
+ import { sha256 as sha2564 } from "@noble/hashes/sha2.js";
4062
3906
  var ERC20_READ_ABI = [
4063
3907
  { name: "balanceOf", type: "function", stateMutability: "view", inputs: [{ name: "account", type: "address" }], outputs: [{ type: "uint256" }] },
4064
3908
  { name: "decimals", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint8" }] },
@@ -4173,6 +4017,62 @@ async function readMinaBalance(opts) {
4173
4017
  assetScale: 9
4174
4018
  };
4175
4019
  }
4020
+ var BASE58_ALPHABET2 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
4021
+ function base58encode(bytes) {
4022
+ let num = 0n;
4023
+ for (const b of bytes) num = num * 256n + BigInt(b);
4024
+ let out = "";
4025
+ while (num > 0n) {
4026
+ out = BASE58_ALPHABET2[Number(num % 58n)] + out;
4027
+ num /= 58n;
4028
+ }
4029
+ for (const b of bytes) {
4030
+ if (b === 0) out = "1" + out;
4031
+ else break;
4032
+ }
4033
+ return out;
4034
+ }
4035
+ function minaTokenIdToBase58(tokenId) {
4036
+ if (!/^\d+$/.test(tokenId)) {
4037
+ throw new Error(`Mina tokenId must be a decimal Field string: "${tokenId}"`);
4038
+ }
4039
+ let field = BigInt(tokenId);
4040
+ const le = new Uint8Array(32);
4041
+ for (let i = 0; i < 32; i++) {
4042
+ le[i] = Number(field & 0xffn);
4043
+ field >>= 8n;
4044
+ }
4045
+ const body = new Uint8Array(1 + 32);
4046
+ body[0] = 28;
4047
+ body.set(le, 1);
4048
+ const checksum = sha2564(sha2564(body)).slice(0, 4);
4049
+ const raw = new Uint8Array(body.length + 4);
4050
+ raw.set(body, 0);
4051
+ raw.set(checksum, body.length);
4052
+ return base58encode(raw);
4053
+ }
4054
+ async function readMinaTokenBalance(opts) {
4055
+ const fetchImpl = opts.fetchImpl ?? fetch;
4056
+ const token = minaTokenIdToBase58(opts.tokenId);
4057
+ const query = "query($pk:PublicKey!,$t:TokenId){account(publicKey:$pk,token:$t){balance{total}}}";
4058
+ const res = await fetchImpl(opts.graphqlUrl, {
4059
+ method: "POST",
4060
+ headers: { "content-type": "application/json" },
4061
+ body: JSON.stringify({ query, variables: { pk: opts.owner, t: token } })
4062
+ });
4063
+ if (!res.ok) throw new Error(`Mina GraphQL request failed: HTTP ${res.status}`);
4064
+ const json = await res.json();
4065
+ if (json.errors && json.errors.length > 0) {
4066
+ throw new Error(`Mina GraphQL error: ${json.errors[0]?.message ?? "unknown"}`);
4067
+ }
4068
+ return {
4069
+ chain: "mina",
4070
+ address: opts.owner,
4071
+ amount: String(json.data?.account?.balance?.total ?? "0"),
4072
+ asset: "USDC",
4073
+ assetScale: 9
4074
+ };
4075
+ }
4176
4076
  var errText = (e) => e instanceof Error ? e.message : String(e);
4177
4077
  function foldNative(out, settled, errors) {
4178
4078
  if (settled.status === "fulfilled") out.native = settled.value;
@@ -4237,24 +4137,28 @@ async function readWalletBalances(sources) {
4237
4137
  );
4238
4138
  }
4239
4139
  if (sources.mina) {
4240
- const { chainKey = "mina", graphqlUrl, owner } = sources.mina;
4140
+ const { chainKey = "mina", graphqlUrl, owner, tokenId } = sources.mina;
4241
4141
  tasks.push(
4242
4142
  (async () => {
4243
4143
  const out = { chain: "mina", chainKey, address: owner, tokens: [] };
4244
4144
  const errors = [];
4245
- const nativeR = await Promise.allSettled([readMinaBalance({ graphqlUrl, owner, fetchImpl })]);
4145
+ const [nativeR, tokenR] = await Promise.allSettled([
4146
+ readMinaBalance({ graphqlUrl, owner, fetchImpl }),
4147
+ tokenId ? readMinaTokenBalance({ graphqlUrl, owner, tokenId, fetchImpl }) : Promise.resolve(void 0)
4148
+ ]);
4246
4149
  foldNative(
4247
4150
  out,
4248
- nativeR[0].status === "fulfilled" ? {
4151
+ nativeR.status === "fulfilled" ? {
4249
4152
  status: "fulfilled",
4250
4153
  value: {
4251
- symbol: nativeR[0].value.asset,
4252
- amount: nativeR[0].value.amount,
4253
- decimals: nativeR[0].value.assetScale
4154
+ symbol: nativeR.value.asset,
4155
+ amount: nativeR.value.amount,
4156
+ decimals: nativeR.value.assetScale
4254
4157
  }
4255
- } : nativeR[0],
4158
+ } : nativeR,
4256
4159
  errors
4257
4160
  );
4161
+ foldToken(out, tokenR, void 0, errors);
4258
4162
  finalizeChain(out, errors);
4259
4163
  return out;
4260
4164
  })()
@@ -4800,7 +4704,7 @@ async function submitEvmSettlement(bundle, params) {
4800
4704
  }
4801
4705
 
4802
4706
  // src/swap/mina-settlement.ts
4803
- import { hexToMinaBase58PrivateKey as hexToMinaBase58PrivateKey4 } from "@toon-protocol/core";
4707
+ import { hexToMinaBase58PrivateKey as hexToMinaBase58PrivateKey3 } from "@toon-protocol/core";
4804
4708
  var MinaSettlementError = class extends Error {
4805
4709
  code;
4806
4710
  constructor(code, message) {
@@ -4869,7 +4773,7 @@ async function buildMinaCoSignedClaim(inputs) {
4869
4773
  balanceB,
4870
4774
  salt
4871
4775
  ).toString();
4872
- const recipientPrivateKeyBase58 = hexToMinaBase58PrivateKey4(
4776
+ const recipientPrivateKeyBase58 = hexToMinaBase58PrivateKey3(
4873
4777
  inputs.recipientPrivateKey
4874
4778
  );
4875
4779
  const built = await buildMinaPaymentChannelProof({
@@ -4996,7 +4900,7 @@ function createO1jsMinaClaimSubmitter() {
4996
4900
  const PaymentChannel = zkAppMod.PaymentChannel;
4997
4901
  Mina.setActiveInstance(Mina.Network(args.graphqlUrl));
4998
4902
  const feePayerKey = PrivateKey.fromBase58(
4999
- hexToMinaBase58PrivateKey4(args.feePayerPrivateKey)
4903
+ hexToMinaBase58PrivateKey3(args.feePayerPrivateKey)
5000
4904
  );
5001
4905
  const feePayerPub = feePayerKey.toPublicKey();
5002
4906
  await PaymentChannel.compile();
@@ -5289,7 +5193,8 @@ var ToonClient = class {
5289
5193
  if (this.config.minaChannel && this.minaPrivateKey) {
5290
5194
  initialization.onChainChannelClient.setMinaConfig({
5291
5195
  graphqlUrl: this.config.minaChannel.graphqlUrl,
5292
- zkAppAddress: this.config.minaChannel.zkAppAddress,
5196
+ ...this.config.minaChannel.zkAppAddress !== void 0 ? { zkAppAddress: this.config.minaChannel.zkAppAddress } : {},
5197
+ ...this.config.minaChannel.autoDeploy !== void 0 ? { autoDeploy: this.config.minaChannel.autoDeploy } : {},
5293
5198
  privateKey: this.minaPrivateKey,
5294
5199
  ...this.config.minaChannel.challengeDuration !== void 0 ? { challengeDuration: this.config.minaChannel.challengeDuration } : {},
5295
5200
  ...this.config.minaChannel.tokenId !== void 0 ? { tokenId: this.config.minaChannel.tokenId } : {},
@@ -5938,7 +5843,12 @@ var ToonClient = class {
5938
5843
  if (mina?.graphqlUrl) {
5939
5844
  const minaAddress = this.getMinaAddress() ?? (await ensureDerived())?.mina.publicKey;
5940
5845
  if (minaAddress) {
5941
- sources.mina = { chainKey: "mina", graphqlUrl: mina.graphqlUrl, owner: minaAddress };
5846
+ sources.mina = {
5847
+ chainKey: "mina",
5848
+ graphqlUrl: mina.graphqlUrl,
5849
+ owner: minaAddress,
5850
+ ...mina.tokenId ? { tokenId: mina.tokenId } : {}
5851
+ };
5942
5852
  }
5943
5853
  }
5944
5854
  return readWalletBalances(sources);
@@ -8027,11 +7937,13 @@ export {
8027
7937
  decodeEvmSettlementTx,
8028
7938
  decryptMnemonic2 as decryptMnemonic,
8029
7939
  defaultFaucetTimeout,
7940
+ deployMinaChannelZkApp,
8030
7941
  deriveFromNsec,
8031
7942
  deriveFullIdentity,
8032
7943
  deriveNostrKeyFromMnemonic,
8033
7944
  deterministicGenerator,
8034
7945
  encryptMnemonic2 as encryptMnemonic,
7946
+ ensureOwnedMinaZkApp,
8035
7947
  entryToAccumulatedClaim,
8036
7948
  evmClaimDigest,
8037
7949
  evmCooperativeCloseDigest,