@dorafactory/maci-sdk 0.1.3-pre.46.beta.1 → 0.1.3-pre.46.beta.10

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
@@ -1247,7 +1247,9 @@ var rerandomize = (pubKey, ciphertext, randomVal = genRandomSalt()) => {
1247
1247
  var genAddKeyInput = (depth, {
1248
1248
  coordPubKey,
1249
1249
  oldKey,
1250
- deactivates
1250
+ deactivates,
1251
+ newPubKey,
1252
+ pollId
1251
1253
  }) => {
1252
1254
  const sharedKeyHash = poseidon(genEcdhSharedKey(oldKey.privKey, coordPubKey));
1253
1255
  const randomVal = genRandomSalt();
@@ -1259,7 +1261,7 @@ var genAddKeyInput = (depth, {
1259
1261
  const c1 = [deactivateLeaf[0], deactivateLeaf[1]];
1260
1262
  const c2 = [deactivateLeaf[2], deactivateLeaf[3]];
1261
1263
  const { d1, d2 } = rerandomize(coordPubKey, { c1, c2 }, randomVal);
1262
- const nullifier = poseidon([BigInt(oldKey.formatedPrivKey), 1444992409218394441042n]);
1264
+ const nullifier = poseidon([BigInt(oldKey.formatedPrivKey), pollId]);
1263
1265
  const tree = new Tree(5, depth, 0n);
1264
1266
  const leaves = deactivates.map((d) => poseidon(d));
1265
1267
  tree.initLeaves(leaves);
@@ -1272,7 +1274,9 @@ var genAddKeyInput = (depth, {
1272
1274
  d1[0],
1273
1275
  d1[1],
1274
1276
  d2[0],
1275
- d2[1]
1277
+ d2[1],
1278
+ poseidon(newPubKey),
1279
+ pollId
1276
1280
  ]);
1277
1281
  const input = {
1278
1282
  inputHash,
@@ -1287,7 +1291,9 @@ var genAddKeyInput = (depth, {
1287
1291
  d2,
1288
1292
  deactivateLeafPathElements,
1289
1293
  nullifier,
1290
- oldPrivateKey: oldKey.formatedPrivKey
1294
+ oldPrivateKey: oldKey.formatedPrivKey,
1295
+ newPubKey,
1296
+ pollId
1291
1297
  };
1292
1298
  return input;
1293
1299
  };
@@ -4342,6 +4348,46 @@ var ApiSaasClient = class extends ApiSaasQueryClient {
4342
4348
  _funds
4343
4349
  );
4344
4350
  };
4351
+ this.publishMessage = async ({
4352
+ contractAddr,
4353
+ encPubKeys,
4354
+ messages
4355
+ }, fee = "auto", memo, _funds) => {
4356
+ return await this.client.execute(
4357
+ this.sender,
4358
+ this.contractAddress,
4359
+ {
4360
+ publish_message: {
4361
+ contract_addr: contractAddr,
4362
+ enc_pub_keys: encPubKeys,
4363
+ messages
4364
+ }
4365
+ },
4366
+ fee,
4367
+ memo,
4368
+ _funds
4369
+ );
4370
+ };
4371
+ this.publishDeactivateMessage = async ({
4372
+ contractAddr,
4373
+ encPubKey,
4374
+ message
4375
+ }, fee = "auto", memo, _funds) => {
4376
+ return await this.client.execute(
4377
+ this.sender,
4378
+ this.contractAddress,
4379
+ {
4380
+ publish_deactivate_message: {
4381
+ contract_addr: contractAddr,
4382
+ enc_pub_key: encPubKey,
4383
+ message
4384
+ }
4385
+ },
4386
+ fee,
4387
+ memo,
4388
+ _funds
4389
+ );
4390
+ };
4345
4391
  this.client = client;
4346
4392
  this.sender = sender;
4347
4393
  this.contractAddress = contractAddress;
@@ -4354,6 +4400,8 @@ var ApiSaasClient = class extends ApiSaasQueryClient {
4354
4400
  this.createAmaciRound = this.createAmaciRound.bind(this);
4355
4401
  this.setRoundInfo = this.setRoundInfo.bind(this);
4356
4402
  this.setVoteOptionsMap = this.setVoteOptionsMap.bind(this);
4403
+ this.publishMessage = this.publishMessage.bind(this);
4404
+ this.publishDeactivateMessage = this.publishDeactivateMessage.bind(this);
4357
4405
  }
4358
4406
  };
4359
4407
 
@@ -4399,7 +4447,6 @@ async function createApiSaasClientBy({
4399
4447
  return new ApiSaasClient(signingCosmWasmClient, address, contractAddress);
4400
4448
  }
4401
4449
  async function createContractClientByWallet(rpcEndpoint, wallet) {
4402
- console.log("rpcEndpoint", rpcEndpoint);
4403
4450
  const client = await import_cosmwasm_stargate.SigningCosmWasmClient.connectWithSigner(rpcEndpoint, wallet, {
4404
4451
  ...defaultSigningClientOptions
4405
4452
  });
@@ -4431,11 +4478,11 @@ function getAMaciRoundCircuitFee(network, maxVoter, maxOption) {
4431
4478
  amount: "0"
4432
4479
  };
4433
4480
  if (maxVoter <= 25 && maxOption <= 5) {
4434
- requiredFee.amount = "20000000000000000000";
4481
+ requiredFee.amount = "5000000000000000000";
4435
4482
  } else if (maxVoter <= 625 && maxOption <= 25) {
4436
- requiredFee.amount = "540000000000000000000";
4483
+ requiredFee.amount = "27000000000000000000";
4437
4484
  } else if (maxVoter <= 15625 && maxOption <= 125) {
4438
- requiredFee.amount = "1080000000000000000000";
4485
+ requiredFee.amount = "208000000000000000000";
4439
4486
  } else {
4440
4487
  throw new Error("Number of voters or options is too large.");
4441
4488
  }
@@ -4515,6 +4562,7 @@ var Contract = class {
4515
4562
  [requiredFee]
4516
4563
  );
4517
4564
  let contractAddress = "";
4565
+ let pollId = "";
4518
4566
  for (const event of res.events) {
4519
4567
  if (event.type === "wasm") {
4520
4568
  const actionEvent = event.attributes.find(
@@ -4524,8 +4572,16 @@ var Contract = class {
4524
4572
  const roundAddrEvent = event.attributes.find(
4525
4573
  (attr) => attr.key === "round_addr"
4526
4574
  );
4575
+ const pollIdEvent = event.attributes.find(
4576
+ (attr) => attr.key === "poll_id"
4577
+ );
4527
4578
  if (roundAddrEvent) {
4528
4579
  contractAddress = roundAddrEvent.value.toString();
4580
+ }
4581
+ if (pollIdEvent) {
4582
+ pollId = pollIdEvent.value.toString();
4583
+ }
4584
+ if (contractAddress) {
4529
4585
  break;
4530
4586
  }
4531
4587
  }
@@ -4533,7 +4589,8 @@ var Contract = class {
4533
4589
  }
4534
4590
  return {
4535
4591
  ...res,
4536
- contractAddress
4592
+ contractAddress,
4593
+ pollId
4537
4594
  };
4538
4595
  }
4539
4596
  async queryRoundInfo({ signer, roundAddress }) {
@@ -4944,6 +5001,7 @@ var Contract = class {
4944
5001
  createResponse = await client.createAmaciRound(roundParams, fee);
4945
5002
  }
4946
5003
  let contractAddress = "";
5004
+ let pollId = "";
4947
5005
  for (const event of createResponse.events) {
4948
5006
  if (event.type === "wasm") {
4949
5007
  const actionEvent = event.attributes.find(
@@ -4953,8 +5011,16 @@ var Contract = class {
4953
5011
  const roundAddrEvent = event.attributes.find(
4954
5012
  (attr) => attr.key === "round_addr"
4955
5013
  );
5014
+ const pollIdEvent = event.attributes.find(
5015
+ (attr) => attr.key === "poll_id"
5016
+ );
4956
5017
  if (roundAddrEvent) {
4957
5018
  contractAddress = roundAddrEvent.value.toString();
5019
+ }
5020
+ if (pollIdEvent) {
5021
+ pollId = pollIdEvent.value.toString();
5022
+ }
5023
+ if (contractAddress) {
4958
5024
  break;
4959
5025
  }
4960
5026
  }
@@ -4962,9 +5028,126 @@ var Contract = class {
4962
5028
  }
4963
5029
  return {
4964
5030
  ...createResponse,
4965
- contractAddress
5031
+ contractAddress,
5032
+ pollId
4966
5033
  };
4967
5034
  }
5035
+ async publishMessageViaSaas({
5036
+ signer,
5037
+ contractAddress,
5038
+ encPubKeys,
5039
+ messages,
5040
+ granter,
5041
+ fee = 1.8
5042
+ }) {
5043
+ const client = await createApiSaasClientBy({
5044
+ rpcEndpoint: this.rpcEndpoint,
5045
+ wallet: signer,
5046
+ contractAddress: this.apiSaasAddress
5047
+ });
5048
+ const saasGranter = granter || this.apiSaasAddress;
5049
+ if (typeof fee !== "object") {
5050
+ const [{ address }] = await signer.getAccounts();
5051
+ const contractClient = await this.contractClient({ signer });
5052
+ const msg = {
5053
+ publish_message: {
5054
+ contract_addr: contractAddress,
5055
+ enc_pub_keys: encPubKeys,
5056
+ messages
5057
+ }
5058
+ };
5059
+ const gasEstimation = await contractClient.simulate(
5060
+ address,
5061
+ [
5062
+ {
5063
+ typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
5064
+ value: {
5065
+ sender: address,
5066
+ contract: this.apiSaasAddress,
5067
+ msg: new TextEncoder().encode(JSON.stringify(msg))
5068
+ }
5069
+ }
5070
+ ],
5071
+ ""
5072
+ );
5073
+ const multiplier = typeof fee === "number" ? fee : 1.8;
5074
+ const gasPrice = import_stargate2.GasPrice.fromString("10000000000peaka");
5075
+ const calculatedFee = (0, import_stargate2.calculateFee)(Math.round(gasEstimation * multiplier), gasPrice);
5076
+ const grantFee = {
5077
+ amount: calculatedFee.amount,
5078
+ gas: calculatedFee.gas,
5079
+ granter: saasGranter
5080
+ };
5081
+ return client.publishMessage({ contractAddr: contractAddress, encPubKeys, messages }, grantFee);
5082
+ } else {
5083
+ const grantFee = {
5084
+ ...fee,
5085
+ granter: saasGranter
5086
+ };
5087
+ return client.publishMessage({ contractAddr: contractAddress, encPubKeys, messages }, grantFee);
5088
+ }
5089
+ }
5090
+ async publishDeactivateMessageViaSaas({
5091
+ signer,
5092
+ contractAddress,
5093
+ encPubKey,
5094
+ message,
5095
+ granter,
5096
+ fee = 1.8
5097
+ }) {
5098
+ const client = await createApiSaasClientBy({
5099
+ rpcEndpoint: this.rpcEndpoint,
5100
+ wallet: signer,
5101
+ contractAddress: this.apiSaasAddress
5102
+ });
5103
+ const saasGranter = granter || this.apiSaasAddress;
5104
+ if (typeof fee !== "object") {
5105
+ const [{ address }] = await signer.getAccounts();
5106
+ const contractClient = await this.contractClient({ signer });
5107
+ const msg = {
5108
+ publish_deactivate_message: {
5109
+ contract_addr: contractAddress,
5110
+ enc_pub_key: encPubKey,
5111
+ message
5112
+ }
5113
+ };
5114
+ const gasEstimation = await contractClient.simulate(
5115
+ address,
5116
+ [
5117
+ {
5118
+ typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
5119
+ value: {
5120
+ sender: address,
5121
+ contract: this.apiSaasAddress,
5122
+ msg: new TextEncoder().encode(JSON.stringify(msg))
5123
+ }
5124
+ }
5125
+ ],
5126
+ ""
5127
+ );
5128
+ const multiplier = typeof fee === "number" ? fee : 1.8;
5129
+ const gasPrice = import_stargate2.GasPrice.fromString("10000000000peaka");
5130
+ const calculatedFee = (0, import_stargate2.calculateFee)(Math.round(gasEstimation * multiplier), gasPrice);
5131
+ const grantFee = {
5132
+ amount: calculatedFee.amount,
5133
+ gas: calculatedFee.gas,
5134
+ granter: saasGranter
5135
+ };
5136
+ return client.publishDeactivateMessage(
5137
+ { contractAddr: contractAddress, encPubKey, message },
5138
+ grantFee
5139
+ );
5140
+ } else {
5141
+ const grantFee = {
5142
+ ...fee,
5143
+ granter: saasGranter
5144
+ };
5145
+ return client.publishDeactivateMessage(
5146
+ { contractAddr: contractAddress, encPubKey, message },
5147
+ grantFee
5148
+ );
5149
+ }
5150
+ }
4968
5151
  };
4969
5152
 
4970
5153
  // src/libs/oracle-certificate/oracle-certificate.ts
@@ -5023,7 +5206,7 @@ var import_tx = require("cosmjs-types/cosmwasm/wasm/v1/tx.js");
5023
5206
  // src/libs/maci/config.ts
5024
5207
  var FEE_DENOM = "peaka";
5025
5208
  var DEACTIVATE_FEE = "10000000000000000000";
5026
- var MESSAGE_FEE = "10000000000000000000";
5209
+ var MESSAGE_FEE = "60000000000000000";
5027
5210
 
5028
5211
  // src/libs/maci/maci.ts
5029
5212
  function isErrorResponse(response) {
@@ -5486,6 +5669,18 @@ var MACI = class {
5486
5669
  if (!address) {
5487
5670
  address = (await signer.getAccounts())[0].address;
5488
5671
  }
5672
+ const msgLength = payload[0]?.msg.length ?? 0;
5673
+ if (msgLength === 7) {
5674
+ return await this.publishMessageBatchLegacy({
5675
+ signer,
5676
+ address,
5677
+ payload,
5678
+ contractAddress,
5679
+ gasStation,
5680
+ granter,
5681
+ fee
5682
+ });
5683
+ }
5489
5684
  return await this.publishMessageBatch({
5490
5685
  signer,
5491
5686
  address,
@@ -5571,34 +5766,29 @@ var MACI = class {
5571
5766
  }));
5572
5767
  const totalFee = (BigInt(MESSAGE_FEE) * BigInt(payload.length)).toString();
5573
5768
  const batchFunds = [{ denom: FEE_DENOM, amount: totalFee }];
5574
- if (gasStation && typeof fee !== "object") {
5769
+ if (gasStation && granter === this.contract.apiSaasAddress) {
5770
+ return this.contract.publishMessageViaSaas({
5771
+ signer,
5772
+ contractAddress,
5773
+ encPubKeys,
5774
+ messages,
5775
+ granter,
5776
+ fee
5777
+ });
5778
+ } else if (gasStation && typeof fee !== "object") {
5575
5779
  const client = await this.contract.contractClient({ signer });
5576
- const encPubKeysBigInt = payload.map((p) => ({
5577
- x: p.encPubkeys[0],
5578
- y: p.encPubkeys[1]
5579
- }));
5580
- const messagesBigInt = payload.map((p) => ({
5581
- data: p.msg
5582
- }));
5583
- const msg = {
5780
+ const msgForSimulate = {
5584
5781
  typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
5585
5782
  value: import_tx.MsgExecuteContract.fromPartial({
5586
5783
  sender: address,
5587
5784
  contract: contractAddress,
5588
5785
  msg: new TextEncoder().encode(
5589
- JSON.stringify(
5590
- stringizing({
5591
- publish_message: {
5592
- enc_pub_keys: encPubKeysBigInt,
5593
- messages: messagesBigInt
5594
- }
5595
- })
5596
- )
5786
+ JSON.stringify({ publish_message: { enc_pub_keys: encPubKeys, messages } })
5597
5787
  ),
5598
5788
  funds: batchFunds
5599
5789
  })
5600
5790
  };
5601
- const gasEstimation = await client.simulate(address, [msg], "");
5791
+ const gasEstimation = await client.simulate(address, [msgForSimulate], "");
5602
5792
  const multiplier = typeof fee === "number" ? fee : 1.8;
5603
5793
  const gasPrice = import_stargate3.GasPrice.fromString("10000000000peaka");
5604
5794
  const calculatedFee = (0, import_stargate3.calculateFee)(Math.round(gasEstimation * multiplier), gasPrice);
@@ -5617,6 +5807,63 @@ var MACI = class {
5617
5807
  }
5618
5808
  return amaciClient.publishMessage({ encPubKeys, messages }, fee, void 0, batchFunds);
5619
5809
  }
5810
+ async publishMessageBatchLegacy({
5811
+ signer,
5812
+ address,
5813
+ payload,
5814
+ contractAddress,
5815
+ gasStation,
5816
+ granter,
5817
+ fee = 1.8
5818
+ }) {
5819
+ if (!address) {
5820
+ address = (await signer.getAccounts())[0].address;
5821
+ }
5822
+ const client = await this.contract.contractClient({ signer });
5823
+ const messages = payload.map((p) => ({
5824
+ data: p.msg
5825
+ }));
5826
+ const encPubKeys = payload.map((p) => ({
5827
+ x: p.encPubkeys[0],
5828
+ y: p.encPubkeys[1]
5829
+ }));
5830
+ const msg = {
5831
+ typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
5832
+ value: import_tx.MsgExecuteContract.fromPartial({
5833
+ sender: address,
5834
+ contract: contractAddress,
5835
+ msg: new TextEncoder().encode(
5836
+ JSON.stringify(
5837
+ stringizing({
5838
+ publish_message_batch: {
5839
+ enc_pub_keys: encPubKeys,
5840
+ messages
5841
+ }
5842
+ })
5843
+ )
5844
+ )
5845
+ })
5846
+ };
5847
+ if (gasStation && typeof fee !== "object") {
5848
+ const gasEstimation = await client.simulate(address, [msg], "");
5849
+ const multiplier = typeof fee === "number" ? fee : 1.8;
5850
+ const gasPrice = import_stargate3.GasPrice.fromString("10000000000peaka");
5851
+ const calculatedFee = (0, import_stargate3.calculateFee)(Math.round(gasEstimation * multiplier), gasPrice);
5852
+ const grantFee = {
5853
+ amount: calculatedFee.amount,
5854
+ gas: calculatedFee.gas,
5855
+ granter: granter || contractAddress
5856
+ };
5857
+ return client.signAndBroadcast(address, [msg], grantFee);
5858
+ } else if (gasStation && typeof fee === "object") {
5859
+ const grantFee = {
5860
+ ...fee,
5861
+ granter: granter || contractAddress
5862
+ };
5863
+ return client.signAndBroadcast(address, [msg], grantFee);
5864
+ }
5865
+ return client.signAndBroadcast(address, [msg], fee);
5866
+ }
5620
5867
  async deactivate({
5621
5868
  signer,
5622
5869
  address,
@@ -5712,10 +5959,23 @@ var MACI = class {
5712
5959
  }) {
5713
5960
  try {
5714
5961
  address = address || (await signer.getAccounts())[0].address;
5715
- const client = await this.contract.contractClient({
5716
- signer
5717
- });
5718
5962
  const { msg, encPubkeys } = payload;
5963
+ if (gasStation === true && granter === this.contract.apiSaasAddress) {
5964
+ return this.contract.publishDeactivateMessageViaSaas({
5965
+ signer,
5966
+ contractAddress,
5967
+ encPubKey: {
5968
+ x: encPubkeys[0].toString(),
5969
+ y: encPubkeys[1].toString()
5970
+ },
5971
+ message: {
5972
+ data: msg.map((m) => m.toString())
5973
+ },
5974
+ granter,
5975
+ fee
5976
+ });
5977
+ }
5978
+ const client = await this.contract.contractClient({ signer });
5719
5979
  const deactivateMsg = stringizing({
5720
5980
  publish_deactivate_message: {
5721
5981
  enc_pub_key: {
@@ -5771,6 +6031,7 @@ var MACI = class {
5771
6031
  }
5772
6032
  async genAddKeyInput({
5773
6033
  maciKeypair,
6034
+ newMaciKeypair,
5774
6035
  contractAddress
5775
6036
  }) {
5776
6037
  const deactivates = await this.fetchAllDeactivateLogs({
@@ -5779,12 +6040,15 @@ var MACI = class {
5779
6040
  const roundInfo = await this.getRoundInfo({
5780
6041
  contractAddress
5781
6042
  });
6043
+ const pollId = await this.getPollId({ contractAddress });
5782
6044
  const circuitPower = roundInfo.circuitPower;
5783
6045
  const stateTreeDepth = Number(circuitPower.split("-")[0]);
5784
6046
  const inputObj = genAddKeyInput(stateTreeDepth + 2, {
5785
6047
  coordPubKey: [BigInt(roundInfo.coordinatorPubkeyX), BigInt(roundInfo.coordinatorPubkeyY)],
5786
6048
  oldKey: maciKeypair,
5787
- deactivates: deactivates.map((d) => d.map(BigInt))
6049
+ deactivates: deactivates.map((d) => d.map(BigInt)),
6050
+ newPubKey: newMaciKeypair.pubKey,
6051
+ pollId: BigInt(pollId)
5788
6052
  });
5789
6053
  return inputObj;
5790
6054
  }
@@ -6429,6 +6693,25 @@ var MaciApiClient = class {
6429
6693
  method: "GET"
6430
6694
  });
6431
6695
  }
6696
+ /**
6697
+ * Get coordinator public key, deactivate root, and voter scale for a round.
6698
+ * Lighter alternative to the full data endpoint when only circuit inputs are needed.
6699
+ */
6700
+ async getPreDeactivateMeta(params) {
6701
+ return this.fetch(`/v1/pre-deactivate/${params.contractAddress}/meta`, {
6702
+ method: "GET"
6703
+ });
6704
+ }
6705
+ /**
6706
+ * Get K-anonymous Merkle proof packages for the specified leaf indices.
6707
+ * The caller should mix the real leaf index with decoy indices to preserve privacy.
6708
+ */
6709
+ async getPreDeactivateProof(contractAddress, indices) {
6710
+ return this.fetch(
6711
+ `/v1/pre-deactivate/${contractAddress}/proof?indices=${indices}`,
6712
+ { method: "GET" }
6713
+ );
6714
+ }
6432
6715
  };
6433
6716
 
6434
6717
  // src/maci.ts
@@ -6789,10 +7072,12 @@ var MaciClient = class {
6789
7072
  }
6790
7073
  async genAddKeyInput({
6791
7074
  contractAddress,
6792
- maciKeypair
7075
+ maciKeypair,
7076
+ newMaciKeypair
6793
7077
  }) {
6794
7078
  return await this.maci.genAddKeyInput({
6795
7079
  maciKeypair: maciKeypair || this.maciKeypair,
7080
+ newMaciKeypair,
6796
7081
  contractAddress
6797
7082
  });
6798
7083
  }
@@ -7497,6 +7782,15 @@ var MaciAccount = class {
7497
7782
 
7498
7783
  // src/voter.ts
7499
7784
  var import_poseidon_cipher3 = require("@zk-kit/poseidon-cipher");
7785
+ function buildKAnonymousIndices(deactivateIdx, voterScale) {
7786
+ const kMax = Math.min(200, Math.floor(voterScale * 0.1) || 1);
7787
+ const pool = Array.from({ length: voterScale }, (_, i) => i).filter((i) => i !== deactivateIdx);
7788
+ for (let i = pool.length - 1; i > 0; i--) {
7789
+ const j = Math.floor(Math.random() * (i + 1));
7790
+ [pool[i], pool[j]] = [pool[j], pool[i]];
7791
+ }
7792
+ return [deactivateIdx, ...pool.slice(0, kMax - 1)].sort((a, b) => a - b).join(",");
7793
+ }
7500
7794
  var VoterClient = class _VoterClient {
7501
7795
  /**
7502
7796
  * @constructor
@@ -7627,7 +7921,7 @@ var VoterClient = class _VoterClient {
7627
7921
  derivePathParams
7628
7922
  }) {
7629
7923
  const plan = this.normalizeVoteOptions(selectedOptions);
7630
- const payload = this.batchGenMessage(stateIdx, operatorPubkey, pollId, plan, derivePathParams);
7924
+ const payload = pollId !== void 0 ? this.batchGenMessage(stateIdx, operatorPubkey, pollId, plan, derivePathParams) : this.legacyBatchGenMessage(stateIdx, operatorPubkey, plan, derivePathParams);
7631
7925
  return stringizing(payload);
7632
7926
  }
7633
7927
  /**
@@ -7728,16 +8022,32 @@ var VoterClient = class _VoterClient {
7728
8022
  stateTreeDepth,
7729
8023
  operatorPubkey,
7730
8024
  deactivates,
8025
+ newPubkey,
8026
+ pollId,
7731
8027
  wasmFile,
7732
8028
  zkeyFile,
7733
8029
  derivePathParams
7734
8030
  }) {
7735
8031
  const [coordPubkeyX, coordPubkeyY] = this.unpackMaciPubkey(operatorPubkey);
7736
- const addKeyInput = await this.genAddKeyInput(stateTreeDepth + 2, {
7737
- coordPubKey: [coordPubkeyX, coordPubkeyY],
7738
- deactivates: deactivates.map((d) => d.map(BigInt)),
7739
- derivePathParams
7740
- });
8032
+ let addKeyInput;
8033
+ if (pollId !== void 0) {
8034
+ if (!newPubkey) {
8035
+ throw new Error("buildAddNewKeyPayload: `newPubkey` is required when `pollId` is provided");
8036
+ }
8037
+ addKeyInput = await this.genAddKeyInput(stateTreeDepth + 2, {
8038
+ coordPubKey: [coordPubkeyX, coordPubkeyY],
8039
+ deactivates: deactivates.map((d) => d.map(BigInt)),
8040
+ newPubKey: newPubkey,
8041
+ pollId,
8042
+ derivePathParams
8043
+ });
8044
+ } else {
8045
+ addKeyInput = await this.legacyGenAddKeyInput(stateTreeDepth + 2, {
8046
+ coordPubKey: [coordPubkeyX, coordPubkeyY],
8047
+ deactivates: deactivates.map((d) => d.map(BigInt)),
8048
+ derivePathParams
8049
+ });
8050
+ }
7741
8051
  if (addKeyInput === null) {
7742
8052
  throw Error("genAddKeyInput failed");
7743
8053
  }
@@ -7758,20 +8068,104 @@ var VoterClient = class _VoterClient {
7758
8068
  stateTreeDepth,
7759
8069
  coordinatorPubkey,
7760
8070
  deactivates,
8071
+ contractAddress,
8072
+ deactivateIdx,
8073
+ voterScale,
8074
+ newPubkey,
8075
+ pollId,
7761
8076
  wasmFile,
7762
8077
  zkeyFile,
7763
8078
  derivePathParams
7764
8079
  }) {
7765
8080
  const [coordPubkeyX, coordPubkeyY] = this.unpackMaciPubkey(coordinatorPubkey);
7766
- const addKeyInput = await this.genPreAddKeyInput(stateTreeDepth + 2, {
7767
- coordPubKey: [coordPubkeyX, coordPubkeyY],
7768
- deactivates: deactivates.map((d) => d.map(BigInt)),
7769
- derivePathParams
8081
+ if (pollId === void 0) {
8082
+ if (!deactivates || deactivates.length === 0) {
8083
+ throw new Error(
8084
+ "buildPreAddNewKeyPayload: `deactivates` is required in legacy mode (pollId omitted)"
8085
+ );
8086
+ }
8087
+ const addKeyInput2 = await this.legacyGenPreAddKeyInput(stateTreeDepth + 2, {
8088
+ coordPubKey: [coordPubkeyX, coordPubkeyY],
8089
+ deactivates: deactivates.map((d) => d.map(BigInt)),
8090
+ derivePathParams
8091
+ });
8092
+ if (addKeyInput2 === null) {
8093
+ throw Error("legacyGenPreAddKeyInput failed, cannot find deactivate idx");
8094
+ }
8095
+ const { proof: proof2 } = await import_snarkjs.groth16.fullProve(addKeyInput2, wasmFile, zkeyFile);
8096
+ const proofHex2 = await adaptToUncompressed(proof2);
8097
+ return {
8098
+ proof: proofHex2,
8099
+ d: [
8100
+ addKeyInput2.d1[0].toString(),
8101
+ addKeyInput2.d1[1].toString(),
8102
+ addKeyInput2.d2[0].toString(),
8103
+ addKeyInput2.d2[1].toString()
8104
+ ],
8105
+ nullifier: addKeyInput2.nullifier.toString()
8106
+ };
8107
+ }
8108
+ if (!newPubkey) {
8109
+ throw new Error("buildPreAddNewKeyPayload: `newPubkey` is required when `pollId` is provided");
8110
+ }
8111
+ const coordPubKey = [coordPubkeyX, coordPubkeyY];
8112
+ let resolvedDeactivates;
8113
+ let preComputedTreeProof;
8114
+ let preComputedLeaf;
8115
+ if (deactivates && deactivates.length > 0) {
8116
+ resolvedDeactivates = deactivates.map((d) => d.map(BigInt));
8117
+ } else {
8118
+ if (!contractAddress) {
8119
+ throw new Error(
8120
+ "buildPreAddNewKeyPayload: `contractAddress` is required when `deactivates` is not provided"
8121
+ );
8122
+ }
8123
+ if (deactivateIdx === void 0) {
8124
+ throw new Error(
8125
+ "buildPreAddNewKeyPayload: `deactivateIdx` is required when `deactivates` is not provided"
8126
+ );
8127
+ }
8128
+ if (voterScale === void 0) {
8129
+ throw new Error(
8130
+ "buildPreAddNewKeyPayload: `voterScale` is required when `deactivates` is not provided"
8131
+ );
8132
+ }
8133
+ const indicesParam = buildKAnonymousIndices(deactivateIdx, voterScale);
8134
+ const proofResp = await this.saasApiClient.getPreDeactivateProof(
8135
+ contractAddress,
8136
+ indicesParam
8137
+ );
8138
+ const pkg = proofResp.proofs.find((p) => p.leafIndex === deactivateIdx);
8139
+ if (!pkg) {
8140
+ throw new Error(
8141
+ `buildPreAddNewKeyPayload: proof package for leafIndex ${deactivateIdx} not found in API response`
8142
+ );
8143
+ }
8144
+ preComputedLeaf = pkg.deactivateLeaf.map(BigInt);
8145
+ preComputedTreeProof = {
8146
+ root: proofResp.root,
8147
+ pathElements: pkg.pathElements
8148
+ };
8149
+ resolvedDeactivates = [];
8150
+ }
8151
+ const genPreAddKeyInputStart = Date.now();
8152
+ const addKeyInput = await this.genPreAddKeyInput(stateTreeDepth + 2, {
8153
+ coordPubKey,
8154
+ deactivates: resolvedDeactivates,
8155
+ newPubKey: newPubkey,
8156
+ pollId,
8157
+ derivePathParams,
8158
+ preComputedTreeProof,
8159
+ preComputedLeaf,
8160
+ deactivateIdx
7770
8161
  });
8162
+ console.log(`[genPreAddKeyInput] elapsed: ${Date.now() - genPreAddKeyInputStart}ms`);
7771
8163
  if (addKeyInput === null) {
7772
8164
  throw Error("genPreAddKeyInput failed, cannot find deactivate idx");
7773
8165
  }
8166
+ const fullProveStart = Date.now();
7774
8167
  const { proof } = await import_snarkjs.groth16.fullProve(addKeyInput, wasmFile, zkeyFile);
8168
+ console.log(`[fullProve] elapsed: ${Date.now() - fullProveStart}ms`);
7775
8169
  const proofHex = await adaptToUncompressed(proof);
7776
8170
  return {
7777
8171
  proof: proofHex,
@@ -7787,6 +8181,8 @@ var VoterClient = class _VoterClient {
7787
8181
  async genAddKeyInput(depth, {
7788
8182
  coordPubKey,
7789
8183
  deactivates,
8184
+ newPubKey,
8185
+ pollId,
7790
8186
  derivePathParams
7791
8187
  }) {
7792
8188
  const signer = this.getSigner(derivePathParams);
@@ -7800,7 +8196,7 @@ var VoterClient = class _VoterClient {
7800
8196
  const c1 = [deactivateLeaf[0], deactivateLeaf[1]];
7801
8197
  const c2 = [deactivateLeaf[2], deactivateLeaf[3]];
7802
8198
  const { d1, d2 } = rerandomize(coordPubKey, { c1, c2 }, randomVal);
7803
- const nullifier = poseidon([signer.getFormatedPrivKey(), 1444992409218394441042n]);
8199
+ const nullifier = poseidon([signer.getFormatedPrivKey(), pollId]);
7804
8200
  const tree = new Tree(5, depth, 0n);
7805
8201
  const leaves = deactivates.map((d) => poseidon(d));
7806
8202
  tree.initLeaves(leaves);
@@ -7813,7 +8209,9 @@ var VoterClient = class _VoterClient {
7813
8209
  d1[0],
7814
8210
  d1[1],
7815
8211
  d2[0],
7816
- d2[1]
8212
+ d2[1],
8213
+ poseidon(newPubKey),
8214
+ pollId
7817
8215
  ]);
7818
8216
  const input = {
7819
8217
  inputHash,
@@ -7828,32 +8226,75 @@ var VoterClient = class _VoterClient {
7828
8226
  d2,
7829
8227
  deactivateLeafPathElements,
7830
8228
  nullifier,
7831
- oldPrivateKey: signer.getFormatedPrivKey()
8229
+ oldPrivateKey: signer.getFormatedPrivKey(),
8230
+ newPubKey,
8231
+ pollId
7832
8232
  };
7833
8233
  return input;
7834
8234
  }
7835
8235
  async genPreAddKeyInput(depth, {
7836
8236
  coordPubKey,
7837
8237
  deactivates,
7838
- derivePathParams
8238
+ newPubKey,
8239
+ pollId,
8240
+ derivePathParams,
8241
+ preComputedTreeProof,
8242
+ preComputedLeaf,
8243
+ deactivateIdx: providedDeactivateIdx
7839
8244
  }) {
8245
+ let t0 = Date.now();
7840
8246
  const signer = this.getSigner(derivePathParams);
7841
- const sharedKeyHash = poseidon(signer.genEcdhSharedKey(coordPubKey));
8247
+ console.log(`[genPreAddKeyInput] getSigner: ${Date.now() - t0}ms`);
8248
+ t0 = Date.now();
7842
8249
  const randomVal = genRandomSalt();
7843
- const deactivateIdx = deactivates.findIndex((d) => d[4] === sharedKeyHash);
7844
- if (deactivateIdx < 0) {
8250
+ let deactivateIdx;
8251
+ if (providedDeactivateIdx !== void 0) {
8252
+ deactivateIdx = providedDeactivateIdx;
8253
+ console.log(
8254
+ `[genPreAddKeyInput] using provided deactivateIdx=${deactivateIdx} (skip search)`
8255
+ );
8256
+ } else {
8257
+ const sharedKeyHash = poseidon(signer.genEcdhSharedKey(coordPubKey));
8258
+ console.log(`[genPreAddKeyInput] genEcdhSharedKey + poseidon: ${Date.now() - t0}ms`);
8259
+ t0 = Date.now();
8260
+ deactivateIdx = deactivates.findIndex((d) => d[4] === sharedKeyHash);
8261
+ if (deactivateIdx < 0) {
8262
+ return null;
8263
+ }
8264
+ console.log(`[genPreAddKeyInput] genRandomSalt + findDeactivateIdx: ${Date.now() - t0}ms`);
8265
+ t0 = Date.now();
8266
+ }
8267
+ const deactivateLeaf = preComputedLeaf ?? deactivates[deactivateIdx];
8268
+ if (!deactivateLeaf) {
7845
8269
  return null;
7846
8270
  }
7847
- const deactivateLeaf = deactivates[deactivateIdx];
7848
8271
  const c1 = [deactivateLeaf[0], deactivateLeaf[1]];
7849
8272
  const c2 = [deactivateLeaf[2], deactivateLeaf[3]];
7850
8273
  const { d1, d2 } = rerandomize(coordPubKey, { c1, c2 }, randomVal);
7851
- const nullifier = poseidon([signer.getFormatedPrivKey(), 1444992409218394441042n]);
7852
- const tree = new Tree(5, depth, 0n);
7853
- const leaves = deactivates.map((d) => poseidon(d));
7854
- tree.initLeaves(leaves);
7855
- const deactivateRoot = tree.root;
7856
- const deactivateLeafPathElements = tree.pathElementOf(deactivateIdx);
8274
+ console.log(`[genPreAddKeyInput] rerandomize: ${Date.now() - t0}ms`);
8275
+ t0 = Date.now();
8276
+ const nullifier = poseidon([signer.getFormatedPrivKey(), pollId]);
8277
+ console.log(`[genPreAddKeyInput] nullifier (poseidon): ${Date.now() - t0}ms`);
8278
+ t0 = Date.now();
8279
+ let deactivateRoot;
8280
+ let deactivateLeafPathElements;
8281
+ if (preComputedTreeProof) {
8282
+ deactivateRoot = BigInt(preComputedTreeProof.root);
8283
+ deactivateLeafPathElements = preComputedTreeProof.pathElements.map(
8284
+ (level) => level.map(BigInt)
8285
+ );
8286
+ console.log(`[genPreAddKeyInput] using preComputedTreeProof (API path)`);
8287
+ } else {
8288
+ const tree = new Tree(5, depth, 0n);
8289
+ const leaves = deactivates.map((d) => poseidon(d));
8290
+ tree.initLeaves(leaves);
8291
+ console.log(`[genPreAddKeyInput] build tree + initLeaves: ${Date.now() - t0}ms`);
8292
+ t0 = Date.now();
8293
+ deactivateRoot = tree.root;
8294
+ deactivateLeafPathElements = tree.pathElementOf(deactivateIdx);
8295
+ console.log(`[genPreAddKeyInput] tree.root + pathElementOf: ${Date.now() - t0}ms`);
8296
+ t0 = Date.now();
8297
+ }
7857
8298
  const inputHash = computeInputHash([
7858
8299
  deactivateRoot,
7859
8300
  poseidon(coordPubKey),
@@ -7861,8 +8302,12 @@ var VoterClient = class _VoterClient {
7861
8302
  d1[0],
7862
8303
  d1[1],
7863
8304
  d2[0],
7864
- d2[1]
8305
+ d2[1],
8306
+ poseidon(newPubKey),
8307
+ pollId
7865
8308
  ]);
8309
+ console.log(`[genPreAddKeyInput] computeInputHash: ${Date.now() - t0}ms`);
8310
+ t0 = Date.now();
7866
8311
  const input = {
7867
8312
  inputHash,
7868
8313
  coordPubKey,
@@ -7876,7 +8321,9 @@ var VoterClient = class _VoterClient {
7876
8321
  d2,
7877
8322
  deactivateLeafPathElements,
7878
8323
  nullifier,
7879
- oldPrivateKey: signer.getFormatedPrivKey()
8324
+ oldPrivateKey: signer.getFormatedPrivKey(),
8325
+ newPubKey,
8326
+ pollId
7880
8327
  };
7881
8328
  return input;
7882
8329
  }
@@ -7897,7 +8344,68 @@ var VoterClient = class _VoterClient {
7897
8344
  nonce = 0,
7898
8345
  derivePathParams
7899
8346
  }) {
7900
- const genMessage = this.genMessageFactory(stateIdx, operatorPubkey, pollId, derivePathParams);
8347
+ const genMessage = pollId !== void 0 ? this.genMessageFactory(stateIdx, operatorPubkey, pollId, derivePathParams) : this.legacyGenMessageFactory(stateIdx, operatorPubkey, derivePathParams);
8348
+ const encAccount = genKeypair();
8349
+ const msg = genMessage(BigInt(encAccount.privKey), nonce, 0, 0, true);
8350
+ return stringizing({
8351
+ msg,
8352
+ encPubkeys: encAccount.pubKey
8353
+ });
8354
+ }
8355
+ // ==================== Legacy Methods (backward-compat, no pollId) ====================
8356
+ legacyGenMessageFactory(stateIdx, operatorPubkey, derivePathParams) {
8357
+ return (encPriKey, nonce, voIdx, newVotes, isLastCmd, salt) => {
8358
+ if (salt === void 0) {
8359
+ salt = BigInt(`0x${import_crypto_js3.default.lib.WordArray.random(7).toString(import_crypto_js3.default.enc.Hex)}`);
8360
+ }
8361
+ const packaged = BigInt(nonce) + (BigInt(stateIdx) << 32n) + (BigInt(voIdx) << 64n) + (BigInt(newVotes) << 96n) + (BigInt(salt) << 192n);
8362
+ const signer = this.getSigner(derivePathParams);
8363
+ let newPubKey;
8364
+ if (isLastCmd) {
8365
+ newPubKey = [0n, 0n];
8366
+ } else {
8367
+ newPubKey = [...signer.getPublicKey().toPoints()];
8368
+ }
8369
+ const hash = poseidon([packaged, ...newPubKey]);
8370
+ const signature = signer.sign(hash);
8371
+ const command = [packaged, ...newPubKey, ...signature.R8, signature.S];
8372
+ const coordPubkey = this.unpackMaciPubkey(operatorPubkey);
8373
+ const message = (0, import_poseidon_cipher3.poseidonEncrypt)(command, genEcdhSharedKey(encPriKey, coordPubkey), 0n);
8374
+ return message;
8375
+ };
8376
+ }
8377
+ legacyBatchGenMessage(stateIdx, operatorPubkey, plan, derivePathParams) {
8378
+ const genMessage = this.legacyGenMessageFactory(stateIdx, operatorPubkey, derivePathParams);
8379
+ const payload = [];
8380
+ for (let i = plan.length - 1; i >= 0; i--) {
8381
+ const p = plan[i];
8382
+ const encAccount = genKeypair();
8383
+ const isLastCmd = i === plan.length - 1;
8384
+ const msg = genMessage(BigInt(encAccount.privKey), i + 1, p[0], p[1], isLastCmd);
8385
+ payload.push({
8386
+ msg,
8387
+ encPubkeys: encAccount.pubKey
8388
+ });
8389
+ }
8390
+ return payload;
8391
+ }
8392
+ legacyBuildVotePayload({
8393
+ stateIdx,
8394
+ operatorPubkey,
8395
+ selectedOptions,
8396
+ derivePathParams
8397
+ }) {
8398
+ const plan = this.normalizeVoteOptions(selectedOptions);
8399
+ const payload = this.legacyBatchGenMessage(stateIdx, operatorPubkey, plan, derivePathParams);
8400
+ return stringizing(payload);
8401
+ }
8402
+ legacyBuildDeactivatePayload({
8403
+ stateIdx,
8404
+ operatorPubkey,
8405
+ nonce = 0,
8406
+ derivePathParams
8407
+ }) {
8408
+ const genMessage = this.legacyGenMessageFactory(stateIdx, operatorPubkey, derivePathParams);
7901
8409
  const encAccount = genKeypair();
7902
8410
  const msg = genMessage(BigInt(encAccount.privKey), nonce, 0, 0, true);
7903
8411
  return stringizing({
@@ -7905,6 +8413,164 @@ var VoterClient = class _VoterClient {
7905
8413
  encPubkeys: encAccount.pubKey
7906
8414
  });
7907
8415
  }
8416
+ async legacyGenAddKeyInput(depth, {
8417
+ coordPubKey,
8418
+ deactivates,
8419
+ derivePathParams
8420
+ }) {
8421
+ const signer = this.getSigner(derivePathParams);
8422
+ const sharedKeyHash = poseidon(signer.genEcdhSharedKey(coordPubKey));
8423
+ const randomVal = genRandomSalt();
8424
+ const deactivateIdx = deactivates.findIndex((d) => d[4] === sharedKeyHash);
8425
+ if (deactivateIdx < 0) {
8426
+ return null;
8427
+ }
8428
+ const deactivateLeaf = deactivates[deactivateIdx];
8429
+ const c1 = [deactivateLeaf[0], deactivateLeaf[1]];
8430
+ const c2 = [deactivateLeaf[2], deactivateLeaf[3]];
8431
+ const { d1, d2 } = rerandomize(coordPubKey, { c1, c2 }, randomVal);
8432
+ const nullifier = poseidon([signer.getFormatedPrivKey(), 1444992409218394441042n]);
8433
+ const tree = new Tree(5, depth, 0n);
8434
+ const leaves = deactivates.map((d) => poseidon(d));
8435
+ tree.initLeaves(leaves);
8436
+ const deactivateRoot = tree.root;
8437
+ const deactivateLeafPathElements = tree.pathElementOf(deactivateIdx);
8438
+ const inputHash = computeInputHash([
8439
+ deactivateRoot,
8440
+ poseidon(coordPubKey),
8441
+ nullifier,
8442
+ d1[0],
8443
+ d1[1],
8444
+ d2[0],
8445
+ d2[1]
8446
+ ]);
8447
+ return {
8448
+ inputHash,
8449
+ coordPubKey,
8450
+ deactivateRoot,
8451
+ deactivateIndex: deactivateIdx,
8452
+ deactivateLeaf: poseidon(deactivateLeaf),
8453
+ c1,
8454
+ c2,
8455
+ randomVal,
8456
+ d1,
8457
+ d2,
8458
+ deactivateLeafPathElements,
8459
+ nullifier,
8460
+ oldPrivateKey: signer.getFormatedPrivKey()
8461
+ };
8462
+ }
8463
+ async legacyGenPreAddKeyInput(depth, {
8464
+ coordPubKey,
8465
+ deactivates,
8466
+ derivePathParams
8467
+ }) {
8468
+ const signer = this.getSigner(derivePathParams);
8469
+ const sharedKeyHash = poseidon(signer.genEcdhSharedKey(coordPubKey));
8470
+ const randomVal = genRandomSalt();
8471
+ const deactivateIdx = deactivates.findIndex((d) => d[4] === sharedKeyHash);
8472
+ if (deactivateIdx < 0) {
8473
+ return null;
8474
+ }
8475
+ const deactivateLeaf = deactivates[deactivateIdx];
8476
+ const c1 = [deactivateLeaf[0], deactivateLeaf[1]];
8477
+ const c2 = [deactivateLeaf[2], deactivateLeaf[3]];
8478
+ const { d1, d2 } = rerandomize(coordPubKey, { c1, c2 }, randomVal);
8479
+ const nullifier = poseidon([signer.getFormatedPrivKey(), 1444992409218394441042n]);
8480
+ const tree = new Tree(5, depth, 0n);
8481
+ const leaves = deactivates.map((d) => poseidon(d));
8482
+ tree.initLeaves(leaves);
8483
+ const deactivateRoot = tree.root;
8484
+ const deactivateLeafPathElements = tree.pathElementOf(deactivateIdx);
8485
+ const inputHash = computeInputHash([
8486
+ deactivateRoot,
8487
+ poseidon(coordPubKey),
8488
+ nullifier,
8489
+ d1[0],
8490
+ d1[1],
8491
+ d2[0],
8492
+ d2[1]
8493
+ ]);
8494
+ return {
8495
+ inputHash,
8496
+ coordPubKey,
8497
+ deactivateRoot,
8498
+ deactivateIndex: deactivateIdx,
8499
+ deactivateLeaf: poseidon(deactivateLeaf),
8500
+ c1,
8501
+ c2,
8502
+ randomVal,
8503
+ d1,
8504
+ d2,
8505
+ deactivateLeafPathElements,
8506
+ nullifier,
8507
+ oldPrivateKey: signer.getFormatedPrivKey()
8508
+ };
8509
+ }
8510
+ /**
8511
+ * Legacy `buildAddNewKeyPayload` — old deactivate+addNewKey flow without `pollId` / `newPubKey`
8512
+ * in the ZK circuit. Use when interacting with contracts that predate the poll-ID upgrade.
8513
+ */
8514
+ async legacyBuildAddNewKeyPayload({
8515
+ stateTreeDepth,
8516
+ operatorPubkey,
8517
+ deactivates,
8518
+ wasmFile,
8519
+ zkeyFile,
8520
+ derivePathParams
8521
+ }) {
8522
+ const [coordPubkeyX, coordPubkeyY] = this.unpackMaciPubkey(operatorPubkey);
8523
+ const addKeyInput = await this.legacyGenAddKeyInput(stateTreeDepth + 2, {
8524
+ coordPubKey: [coordPubkeyX, coordPubkeyY],
8525
+ deactivates: deactivates.map((d) => d.map(BigInt)),
8526
+ derivePathParams
8527
+ });
8528
+ if (addKeyInput === null) {
8529
+ throw Error("legacyGenAddKeyInput failed, cannot find deactivate idx");
8530
+ }
8531
+ const { proof } = await import_snarkjs.groth16.fullProve(addKeyInput, wasmFile, zkeyFile);
8532
+ const proofHex = await adaptToUncompressed(proof);
8533
+ return {
8534
+ proof: proofHex,
8535
+ d: [
8536
+ addKeyInput.d1[0].toString(),
8537
+ addKeyInput.d1[1].toString(),
8538
+ addKeyInput.d2[0].toString(),
8539
+ addKeyInput.d2[1].toString()
8540
+ ],
8541
+ nullifier: addKeyInput.nullifier.toString()
8542
+ };
8543
+ }
8544
+ async legacyBuildPreAddNewKeyPayload({
8545
+ stateTreeDepth,
8546
+ coordinatorPubkey,
8547
+ deactivates,
8548
+ wasmFile,
8549
+ zkeyFile,
8550
+ derivePathParams
8551
+ }) {
8552
+ const [coordPubkeyX, coordPubkeyY] = this.unpackMaciPubkey(coordinatorPubkey);
8553
+ const addKeyInput = await this.legacyGenPreAddKeyInput(stateTreeDepth + 2, {
8554
+ coordPubKey: [coordPubkeyX, coordPubkeyY],
8555
+ deactivates: deactivates.map((d) => d.map(BigInt)),
8556
+ derivePathParams
8557
+ });
8558
+ if (addKeyInput === null) {
8559
+ throw Error("legacyGenPreAddKeyInput failed, cannot find deactivate idx");
8560
+ }
8561
+ const { proof } = await import_snarkjs.groth16.fullProve(addKeyInput, wasmFile, zkeyFile);
8562
+ const proofHex = await adaptToUncompressed(proof);
8563
+ return {
8564
+ proof: proofHex,
8565
+ d: [
8566
+ addKeyInput.d1[0].toString(),
8567
+ addKeyInput.d1[1].toString(),
8568
+ addKeyInput.d2[0].toString(),
8569
+ addKeyInput.d2[1].toString()
8570
+ ],
8571
+ nullifier: addKeyInput.nullifier.toString()
8572
+ };
8573
+ }
7908
8574
  // ==================== SaaS API Client Methods ====================
7909
8575
  /**
7910
8576
  * Create a MACI round via SaaS API
@@ -7995,8 +8661,14 @@ var VoterClient = class _VoterClient {
7995
8661
  }
7996
8662
  // ==================== Maci Voter Methods ====================
7997
8663
  /**
7998
- * Pre-create a new account for AMACI voting (pre-deactivate mode)
7999
- * @param params - Parameters including contract address, deactivates, circuit files, and ticket
8664
+ * Pre-create a new account for AMACI voting (pre-deactivate mode).
8665
+ *
8666
+ * Two modes are supported:
8667
+ * - **Local mode**: pass `deactivates` to build the Merkle tree locally (original behaviour).
8668
+ * - **API mode**: omit `deactivates` and the proof will be fetched from the SaaS API using
8669
+ * `contractAddress` (K-anonymous request).
8670
+ *
8671
+ * @param params - Parameters including contract address, optional deactivates, circuit files, and ticket
8000
8672
  * @returns Result with transaction details and new voter account
8001
8673
  */
8002
8674
  async saasPreCreateNewAccount({
@@ -8004,32 +8676,41 @@ var VoterClient = class _VoterClient {
8004
8676
  stateTreeDepth,
8005
8677
  coordinatorPubkey,
8006
8678
  deactivates,
8679
+ deactivateIdx,
8680
+ voterScale,
8681
+ pollId,
8007
8682
  wasmFile,
8008
8683
  zkeyFile,
8009
8684
  ticket,
8010
8685
  derivePathParams
8011
8686
  }) {
8687
+ const newVoterClient = new _VoterClient({
8688
+ network: this.network,
8689
+ restEndpoint: this.restEndpoint,
8690
+ apiEndpoint: this.apiEndpoint,
8691
+ saasApiEndpoint: this.saasApiEndpoint,
8692
+ registryAddress: this.registryAddress
8693
+ });
8694
+ const newPubkey = newVoterClient.getPubkey().toPoints();
8012
8695
  const addNewKeyPayload = await this.buildPreAddNewKeyPayload({
8013
8696
  stateTreeDepth,
8014
8697
  coordinatorPubkey,
8015
8698
  deactivates,
8699
+ contractAddress,
8700
+ deactivateIdx,
8701
+ voterScale,
8702
+ newPubkey,
8703
+ pollId: pollId !== void 0 ? BigInt(pollId) : void 0,
8016
8704
  wasmFile,
8017
8705
  zkeyFile,
8018
8706
  derivePathParams
8019
8707
  });
8020
- const newVoterClient = new _VoterClient({
8021
- network: this.network,
8022
- restEndpoint: this.restEndpoint,
8023
- apiEndpoint: this.apiEndpoint,
8024
- saasApiEndpoint: this.saasApiEndpoint,
8025
- registryAddress: this.registryAddress
8026
- });
8027
8708
  const addNewKeyResult = await newVoterClient.saasSubmitPreAddNewKey({
8028
8709
  contractAddress,
8029
8710
  proof: addNewKeyPayload.proof,
8030
8711
  d: addNewKeyPayload.d,
8031
8712
  nullifier: addNewKeyPayload.nullifier,
8032
- newPubkey: newVoterClient.getPubkey().toPoints().map((p) => p.toString()),
8713
+ newPubkey: newPubkey.map((p) => p.toString()),
8033
8714
  ticket
8034
8715
  });
8035
8716
  return {
@@ -8047,22 +8728,19 @@ var VoterClient = class _VoterClient {
8047
8728
  operatorPubkey,
8048
8729
  selectedOptions,
8049
8730
  ticket,
8731
+ pollId,
8732
+ stateIdx,
8050
8733
  derivePathParams
8051
8734
  }) {
8052
- const stateIdx = await this.getStateIdx({
8053
- contractAddress,
8054
- derivePathParams
8055
- });
8056
- if (stateIdx === -1) {
8735
+ const resolvedStateIdx = stateIdx !== void 0 ? stateIdx : await this.getStateIdx({ contractAddress, derivePathParams });
8736
+ if (resolvedStateIdx === -1) {
8057
8737
  throw new Error("State index is not set, Please signup or addNewKey first");
8058
8738
  }
8059
- const pollId = await this.getPollId(contractAddress);
8060
8739
  const payload = this.buildVotePayload({
8061
- stateIdx,
8740
+ stateIdx: resolvedStateIdx,
8062
8741
  operatorPubkey,
8063
8742
  selectedOptions,
8064
8743
  pollId,
8065
- // Pass pollId instead of contractAddress
8066
8744
  derivePathParams
8067
8745
  });
8068
8746
  const voteResult = await this.saasSubmitVote({
@@ -8278,6 +8956,8 @@ var OperatorClient = class {
8278
8956
  stateTreeDepth,
8279
8957
  operatorPubkey,
8280
8958
  deactivates,
8959
+ newPubkey,
8960
+ pollId,
8281
8961
  wasmFile,
8282
8962
  zkeyFile,
8283
8963
  derivePathParams
@@ -8286,6 +8966,8 @@ var OperatorClient = class {
8286
8966
  const addKeyInput = await this.genAddKeyInput(stateTreeDepth + 2, {
8287
8967
  coordPubKey: [coordPubkeyX, coordPubkeyY],
8288
8968
  deactivates: deactivates.map((d) => d.map(BigInt)),
8969
+ newPubKey: newPubkey,
8970
+ pollId,
8289
8971
  derivePathParams
8290
8972
  });
8291
8973
  if (addKeyInput === null) {
@@ -8308,6 +8990,8 @@ var OperatorClient = class {
8308
8990
  stateTreeDepth,
8309
8991
  coordinatorPubkey,
8310
8992
  deactivates,
8993
+ newPubkey,
8994
+ pollId,
8311
8995
  wasmFile,
8312
8996
  zkeyFile,
8313
8997
  derivePathParams
@@ -8316,6 +9000,8 @@ var OperatorClient = class {
8316
9000
  const addKeyInput = await this.genPreAddKeyInput(stateTreeDepth + 2, {
8317
9001
  coordPubKey: [coordPubkeyX, coordPubkeyY],
8318
9002
  deactivates: deactivates.map((d) => d.map(BigInt)),
9003
+ newPubKey: newPubkey,
9004
+ pollId,
8319
9005
  derivePathParams
8320
9006
  });
8321
9007
  if (addKeyInput === null) {
@@ -8337,6 +9023,8 @@ var OperatorClient = class {
8337
9023
  async genAddKeyInput(depth, {
8338
9024
  coordPubKey,
8339
9025
  deactivates,
9026
+ newPubKey,
9027
+ pollId,
8340
9028
  derivePathParams
8341
9029
  }) {
8342
9030
  const signer = this.getSigner(derivePathParams);
@@ -8350,7 +9038,7 @@ var OperatorClient = class {
8350
9038
  const c1 = [deactivateLeaf[0], deactivateLeaf[1]];
8351
9039
  const c2 = [deactivateLeaf[2], deactivateLeaf[3]];
8352
9040
  const { d1, d2 } = rerandomize(coordPubKey, { c1, c2 }, randomVal);
8353
- const nullifier = poseidon([signer.getFormatedPrivKey(), 1444992409218394441042n]);
9041
+ const nullifier = poseidon([signer.getFormatedPrivKey(), pollId]);
8354
9042
  const tree = new Tree(5, depth, 0n);
8355
9043
  const leaves = deactivates.map((d) => poseidon(d));
8356
9044
  tree.initLeaves(leaves);
@@ -8363,7 +9051,9 @@ var OperatorClient = class {
8363
9051
  d1[0],
8364
9052
  d1[1],
8365
9053
  d2[0],
8366
- d2[1]
9054
+ d2[1],
9055
+ poseidon(newPubKey),
9056
+ pollId
8367
9057
  ]);
8368
9058
  const input = {
8369
9059
  inputHash,
@@ -8378,13 +9068,17 @@ var OperatorClient = class {
8378
9068
  d2,
8379
9069
  deactivateLeafPathElements,
8380
9070
  nullifier,
8381
- oldPrivateKey: signer.getFormatedPrivKey()
9071
+ oldPrivateKey: signer.getFormatedPrivKey(),
9072
+ newPubKey,
9073
+ pollId
8382
9074
  };
8383
9075
  return input;
8384
9076
  }
8385
9077
  async genPreAddKeyInput(depth, {
8386
9078
  coordPubKey,
8387
9079
  deactivates,
9080
+ newPubKey,
9081
+ pollId,
8388
9082
  derivePathParams
8389
9083
  }) {
8390
9084
  const signer = this.getSigner(derivePathParams);
@@ -8398,7 +9092,7 @@ var OperatorClient = class {
8398
9092
  const c1 = [deactivateLeaf[0], deactivateLeaf[1]];
8399
9093
  const c2 = [deactivateLeaf[2], deactivateLeaf[3]];
8400
9094
  const { d1, d2 } = rerandomize(coordPubKey, { c1, c2 }, randomVal);
8401
- const nullifier = poseidon([signer.getFormatedPrivKey(), 1444992409218394441042n]);
9095
+ const nullifier = poseidon([signer.getFormatedPrivKey(), pollId]);
8402
9096
  const tree = new Tree(5, depth, 0n);
8403
9097
  const leaves = deactivates.map((d) => poseidon(d));
8404
9098
  tree.initLeaves(leaves);
@@ -8411,7 +9105,9 @@ var OperatorClient = class {
8411
9105
  d1[0],
8412
9106
  d1[1],
8413
9107
  d2[0],
8414
- d2[1]
9108
+ d2[1],
9109
+ poseidon(newPubKey),
9110
+ pollId
8415
9111
  ]);
8416
9112
  const input = {
8417
9113
  inputHash,
@@ -8426,7 +9122,9 @@ var OperatorClient = class {
8426
9122
  d2,
8427
9123
  deactivateLeafPathElements,
8428
9124
  nullifier,
8429
- oldPrivateKey: signer.getFormatedPrivKey()
9125
+ oldPrivateKey: signer.getFormatedPrivKey(),
9126
+ newPubKey,
9127
+ pollId
8430
9128
  };
8431
9129
  return input;
8432
9130
  }
@@ -8445,7 +9143,13 @@ var OperatorClient = class {
8445
9143
  pollId,
8446
9144
  derivePathParams
8447
9145
  }) {
8448
- const payload = this.batchGenMessage(stateIdx, operatorPubkey, [[0, 0]], pollId, derivePathParams);
9146
+ const payload = this.batchGenMessage(
9147
+ stateIdx,
9148
+ operatorPubkey,
9149
+ [[0, 0]],
9150
+ pollId,
9151
+ derivePathParams
9152
+ );
8449
9153
  return stringizing(payload[0]);
8450
9154
  }
8451
9155
  /**
@@ -8549,10 +9253,10 @@ var OperatorClient = class {
8549
9253
  }
8550
9254
  /**
8551
9255
  * Decrypt message to command
8552
- *
9256
+ *
8553
9257
  * Message structure after decryption (7 elements):
8554
9258
  * [packed_data, newPubKey_x, newPubKey_y, salt, sig_R8_x, sig_R8_y, sig_S]
8555
- *
9259
+ *
8556
9260
  * Packed data contains (from low to high bits):
8557
9261
  * - nonce (bits 0-31)
8558
9262
  * - stateIdx (bits 32-63)
@@ -8949,6 +9653,19 @@ var OperatorClient = class {
8949
9653
  throw new Error("Poll ID not set. Ensure initRound was called with pollId parameter.");
8950
9654
  }
8951
9655
  const batchSize = this.batchSize;
9656
+ if (this.msgEndIdx === 0) {
9657
+ this.endProcessingPeriod();
9658
+ const newStateRoot2 = this.stateTree.root;
9659
+ const newStateCommitment2 = poseidon([newStateRoot2, newStateSalt]);
9660
+ this.stateCommitment = newStateCommitment2;
9661
+ return {
9662
+ input: {
9663
+ newStateCommitment: newStateCommitment2,
9664
+ packedVals: BigInt(this.maxVoteOptions) + (BigInt(this.numSignUps) << 32n) + (this.isQuadraticCost ? 1n << 64n : 0n)
9665
+ },
9666
+ proof: null
9667
+ };
9668
+ }
8952
9669
  const batchStartIdx = Math.floor((this.msgEndIdx - 1) / batchSize) * batchSize;
8953
9670
  const batchEndIdx = Math.min(batchStartIdx + batchSize, this.msgEndIdx);
8954
9671
  console.log(`Process messages [${batchStartIdx}, ${batchEndIdx})`);