@dorafactory/maci-sdk 0.0.19 → 0.0.21

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.mjs CHANGED
@@ -187,11 +187,12 @@ var Http = class {
187
187
  );
188
188
  }
189
189
  }
190
- async fetchRest(path) {
190
+ async fetchRest(path, options) {
191
191
  try {
192
192
  const fetchFn = this.getFetch();
193
193
  const response = await fetchFn(`${this.restEndpoint}${path}`, {
194
- ...this.defaultOptions
194
+ ...this.defaultOptions,
195
+ ...options
195
196
  });
196
197
  if (!response.ok) {
197
198
  throw new HttpError(
@@ -222,6 +223,8 @@ var ERROR = {
222
223
  ERROR_CIRCUIT_NOT_FOUND: "ERROR_CIRCUIT_NOT_FOUND",
223
224
  ERROR_OPERATOR_INVALID_ADDRESS: "ERROR_OPERATOR_INVALID_ADDRESS",
224
225
  ERROR_OPERATOR_NOT_FOUND: "ERROR_OPERATOR_NOT_FOUND",
226
+ ERROR_OPERATOR_DELAY_HISTORY_NOT_FOUND: "ERROR_OPERATOR_DELAY_HISTORY_NOT_FOUND",
227
+ ERROR_QUERY_MISS_RATE_FAILED: "ERROR_QUERY_MISS_RATE_FAILED",
225
228
  ERROR_OPERATORS_NOT_FOUND: "ERROR_OPERATORS_NOT_FOUND",
226
229
  ERROR_PROOF_NOT_FOUND: "ERROR_PROOF_NOT_FOUND",
227
230
  ERROR_ROUND_INVALID_ADDRESS: "ERROR_ROUND_INVALID_ADDRESS",
@@ -648,6 +651,64 @@ var Operator = class {
648
651
  return handleError(error);
649
652
  }
650
653
  }
654
+ async getOperatorDelayOperationsByAddress(address, after, limit) {
655
+ try {
656
+ if (!isValidAddress(address)) {
657
+ return {
658
+ code: 400,
659
+ error: {
660
+ message: "Invalid operator address format",
661
+ type: ERROR.ERROR_OPERATOR_INVALID_ADDRESS
662
+ }
663
+ };
664
+ }
665
+ const OPERATORS_QUERY = `query ($limit: Int, $after: Cursor) {
666
+ operatorDelayOperations(first: $limit, after: $after, filter: {operatorAddress: {equalTo: "${address}"}}, orderBy: [TIMESTAMP_DESC]) {
667
+ pageInfo {
668
+ endCursor
669
+ hasNextPage
670
+ }
671
+ totalCount
672
+ edges {
673
+ cursor
674
+ node {
675
+ blockHeight
676
+ delayProcessDmsgCount
677
+ delayDuration
678
+ delayReason
679
+ delayType
680
+ id
681
+ nodeId
682
+ operatorAddress
683
+ timestamp
684
+ roundAddress
685
+ }
686
+ }
687
+ }
688
+ }`;
689
+ const response = await this.http.fetchGraphql(
690
+ OPERATORS_QUERY,
691
+ after,
692
+ limit
693
+ );
694
+ if (!response || !response.data || !response.data.operatorDelayOperations || !response.data.operatorDelayOperations.edges || response.data.operatorDelayOperations.edges.length === 0) {
695
+ return {
696
+ code: 404,
697
+ error: {
698
+ message: `No operatorDelayOperations found for address ${address}`,
699
+ type: ERROR.ERROR_OPERATOR_DELAY_HISTORY_NOT_FOUND
700
+ }
701
+ };
702
+ }
703
+ const operator = {
704
+ code: 200,
705
+ data: response.data
706
+ };
707
+ return operator;
708
+ } catch (error) {
709
+ return handleError(error);
710
+ }
711
+ }
651
712
  async getOperators(after, limit) {
652
713
  try {
653
714
  const OPERATORS_QUERY = `query ($limit: Int, $after: Cursor) {
@@ -751,6 +812,228 @@ var Operator = class {
751
812
  return handleError(error);
752
813
  }
753
814
  }
815
+ async queryMissRate(address, durationDay) {
816
+ try {
817
+ const now = /* @__PURE__ */ new Date();
818
+ const startTime = new Date(
819
+ now.getTime() - durationDay * 24 * 60 * 60 * 1e3
820
+ );
821
+ const startTimestamp = Math.floor(startTime.getTime() / 1e3);
822
+ const endNanosTimestamp = Math.floor(startTime.getTime() * 1e6);
823
+ const txTimestamp = Math.floor(startTime.getTime());
824
+ const QUERY = `query ($limit: Int, $after: Cursor) {
825
+ operatorDelayOperations(
826
+ first: $limit,
827
+ after: $after,
828
+ filter: {
829
+ operatorAddress: {equalTo: "${address}"},
830
+ timestamp: { greaterThanOrEqualTo: "${startTimestamp}" }
831
+ },
832
+ orderBy: [TIMESTAMP_DESC]
833
+ ) {
834
+ edges {
835
+ node {
836
+ blockHeight
837
+ delayProcessDmsgCount
838
+ delayDuration
839
+ delayReason
840
+ delayType
841
+ id
842
+ nodeId
843
+ operatorAddress
844
+ timestamp
845
+ roundAddress
846
+ }
847
+ }
848
+ }
849
+ }`;
850
+ const ROUNDS_QUERY = `query ($limit: Int, $after: Cursor) {
851
+ rounds(first: $limit, after: $after,
852
+ filter: {
853
+ operator: {equalTo: "${address}"},
854
+ votingEnd: { greaterThanOrEqualTo: "${endNanosTimestamp}" }
855
+ },
856
+ orderBy: [TIMESTAMP_DESC]
857
+ ){
858
+ pageInfo {
859
+ endCursor
860
+ hasNextPage
861
+ }
862
+ totalCount
863
+ edges {
864
+ node {
865
+ id
866
+ blockHeight
867
+ txHash
868
+ caller
869
+ admin
870
+ operator
871
+ contractAddress
872
+ circuitName
873
+ timestamp
874
+ votingStart
875
+ votingEnd
876
+ status
877
+ period
878
+ actionType
879
+ roundTitle
880
+ roundDescription
881
+ roundLink
882
+ coordinatorPubkeyX
883
+ coordinatorPubkeyY
884
+ voteOptionMap
885
+ results
886
+ allResult
887
+ gasStationEnable
888
+ totalGrant
889
+ baseGrant
890
+ totalBond
891
+ circuitType
892
+ circuitPower
893
+ certificationSystem
894
+ codeId
895
+ maciType
896
+ voiceCreditAmount
897
+ preDeactivateRoot
898
+ }
899
+ cursor
900
+ }
901
+ }
902
+ }
903
+ `;
904
+ const roundsResponse = await this.http.fetchGraphql(
905
+ ROUNDS_QUERY,
906
+ "",
907
+ 9999
908
+ );
909
+ const roundContractAddresses = roundsResponse?.data?.rounds?.edges?.map(
910
+ (edge) => edge.node.contractAddress
911
+ ) || [];
912
+ const TRANSACTIONS_QUERY = `query transactions($limit: Int, $after: Cursor) {
913
+ transactions(first: $limit, after: $after,
914
+ filter: {
915
+ timestamp: { greaterThanOrEqualTo: "${txTimestamp}" },
916
+ type: { equalTo: "op:procDeactivate" },
917
+ contractAddress: { in: ${JSON.stringify(roundContractAddresses)} }
918
+ },
919
+ orderBy: [TIMESTAMP_DESC]
920
+ ){
921
+ pageInfo {
922
+ endCursor
923
+ hasNextPage
924
+ }
925
+ totalCount
926
+ edges {
927
+ cursor
928
+ node {
929
+ id
930
+ blockHeight
931
+ txHash
932
+ timestamp
933
+ type
934
+ status
935
+ circuitName
936
+ fee
937
+ gasUsed
938
+ gasWanted
939
+ caller
940
+ contractAddress
941
+ }
942
+ }
943
+ }
944
+ }`;
945
+ const [delayResponse, transactionsResponse] = await Promise.all([
946
+ this.http.fetchGraphql(
947
+ QUERY,
948
+ "",
949
+ 9999
950
+ ),
951
+ this.http.fetchGraphql(
952
+ TRANSACTIONS_QUERY,
953
+ "",
954
+ 9999
955
+ )
956
+ ]);
957
+ const dailyStats = /* @__PURE__ */ new Map();
958
+ const endDate = /* @__PURE__ */ new Date();
959
+ for (let i = 0; i < durationDay; i++) {
960
+ const date = new Date(endDate.getTime() - i * 24 * 60 * 60 * 1e3).toISOString().split("T")[0];
961
+ dailyStats.set(date, {
962
+ delayCount: 0,
963
+ deactivateDelay: {
964
+ count: 0,
965
+ dmsgCount: 0
966
+ },
967
+ tallyDelay: {
968
+ count: 0
969
+ },
970
+ totalDelayDuration: 0,
971
+ avgDelayDuration: 0,
972
+ tallyCount: 0,
973
+ deactivateCount: 0,
974
+ missRate: 0
975
+ });
976
+ }
977
+ delayResponse.data.operatorDelayOperations.edges.forEach(({ node }) => {
978
+ const date = new Date(parseInt(node.timestamp) * 1e3).toISOString().split("T")[0];
979
+ if (dailyStats.has(date)) {
980
+ const stats = dailyStats.get(date);
981
+ stats.delayCount++;
982
+ stats.totalDelayDuration += parseInt(node.delayDuration);
983
+ if (node.delayType === "deactivate_delay") {
984
+ stats.deactivateDelay.count++;
985
+ stats.deactivateDelay.dmsgCount += node.delayProcessDmsgCount;
986
+ } else if (node.delayType === "tally_delay") {
987
+ stats.tallyDelay.count++;
988
+ }
989
+ }
990
+ });
991
+ if (roundsResponse?.data?.rounds?.edges) {
992
+ roundsResponse.data.rounds.edges.forEach(({ node }) => {
993
+ const date = new Date(parseInt(node.votingEnd) / 1e6).toISOString().split("T")[0];
994
+ if (dailyStats.has(date)) {
995
+ const stats = dailyStats.get(date);
996
+ stats.tallyCount++;
997
+ }
998
+ });
999
+ }
1000
+ if (transactionsResponse?.data?.transactions?.edges) {
1001
+ transactionsResponse.data.transactions.edges.forEach(({ node }) => {
1002
+ const date = new Date(parseInt(node.timestamp)).toISOString().split("T")[0];
1003
+ if (dailyStats.has(date)) {
1004
+ const stats = dailyStats.get(date);
1005
+ stats.deactivateCount++;
1006
+ }
1007
+ });
1008
+ }
1009
+ return {
1010
+ code: 200,
1011
+ data: {
1012
+ missRate: Array.from(dailyStats.entries()).map(([date, stats]) => ({
1013
+ date,
1014
+ delayCount: stats.delayCount,
1015
+ deactivateDelay: stats.deactivateDelay,
1016
+ tallyDelay: stats.tallyDelay,
1017
+ totalDelayDuration: stats.totalDelayDuration,
1018
+ avgDelayDuration: stats.delayCount > 0 ? stats.totalDelayDuration / stats.delayCount : 0,
1019
+ tallyCount: stats.tallyCount,
1020
+ deactivateCount: stats.deactivateCount,
1021
+ missRate: stats.deactivateCount + stats.tallyCount > 0 ? parseFloat(
1022
+ ((stats.deactivateDelay.count + stats.tallyDelay.count) / (stats.deactivateCount + stats.tallyCount)).toFixed(2)
1023
+ ) : 0
1024
+ })).sort((a, b) => b.date.localeCompare(a.date))
1025
+ }
1026
+ };
1027
+ } catch (error) {
1028
+ return {
1029
+ code: 404,
1030
+ error: {
1031
+ message: "Query miss rate failed",
1032
+ type: ERROR.ERROR_QUERY_MISS_RATE_FAILED
1033
+ }
1034
+ };
1035
+ }
1036
+ }
754
1037
  };
755
1038
 
756
1039
  // src/libs/query/round.ts
@@ -1578,6 +1861,16 @@ var Indexer = class {
1578
1861
  async getOperatorByAddress(address) {
1579
1862
  return await this.operator.getOperatorByAddress(address);
1580
1863
  }
1864
+ async getOperatorDelayOperationsByAddress(address, after, limit) {
1865
+ return await this.operator.getOperatorDelayOperationsByAddress(
1866
+ address,
1867
+ after,
1868
+ limit
1869
+ );
1870
+ }
1871
+ async queryMissRate(address, durationDay) {
1872
+ return await this.operator.queryMissRate(address, durationDay);
1873
+ }
1581
1874
  /**
1582
1875
  * @method getOperators
1583
1876
  * @description Get multiple operators.
@@ -3719,7 +4012,7 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3719
4012
  `Invalid proof system ${proofSystem}, only support GROTH16 and PLONK`
3720
4013
  );
3721
4014
  }
3722
- if (Number(maxVoter) <= 25 && Number(maxOption) <= 5) {
4015
+ if (maxVoter <= 25 && maxOption <= 5) {
3723
4016
  parameters = CIRCUIT_INFO["2-1-1-5"].parameter;
3724
4017
  if (proofSystem === "groth16" /* GROTH16 */) {
3725
4018
  groth16ProcessVkey = CIRCUIT_INFO["2-1-1-5"]["groth16"].process_vkey;
@@ -3728,7 +4021,7 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3728
4021
  plonkProcessVkey = CIRCUIT_INFO["2-1-1-5"]["plonk"]?.process_vkey;
3729
4022
  plonkTallyVkey = CIRCUIT_INFO["2-1-1-5"]["plonk"]?.tally_vkey;
3730
4023
  }
3731
- } else if (Number(maxVoter) <= 625 && Number(maxOption) <= 25) {
4024
+ } else if (maxVoter <= 625 && maxOption <= 25) {
3732
4025
  parameters = CIRCUIT_INFO["4-2-2-25"].parameter;
3733
4026
  if (proofSystem === "groth16" /* GROTH16 */) {
3734
4027
  groth16ProcessVkey = CIRCUIT_INFO["4-2-2-25"]["groth16"].process_vkey;
@@ -3737,7 +4030,7 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3737
4030
  plonkProcessVkey = CIRCUIT_INFO["4-2-2-25"]["plonk"]?.process_vkey;
3738
4031
  plonkTallyVkey = CIRCUIT_INFO["4-2-2-25"]["plonk"]?.tally_vkey;
3739
4032
  }
3740
- } else if (Number(maxVoter) <= 15625 && Number(maxOption) <= 125) {
4033
+ } else if (maxVoter <= 15625 && maxOption <= 125) {
3741
4034
  parameters = CIRCUIT_INFO["6-3-3-125"].parameter;
3742
4035
  if (proofSystem === "groth16" /* GROTH16 */) {
3743
4036
  groth16ProcessVkey = CIRCUIT_INFO["6-3-3-125"]["groth16"].process_vkey;
@@ -3746,7 +4039,7 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3746
4039
  plonkProcessVkey = CIRCUIT_INFO["6-3-3-125"]["plonk"]?.process_vkey;
3747
4040
  plonkTallyVkey = CIRCUIT_INFO["6-3-3-125"]["plonk"]?.tally_vkey;
3748
4041
  }
3749
- } else if (Number(maxVoter) <= 1953125 && Number(maxOption) <= 125) {
4042
+ } else if (maxVoter <= 1953125 && maxOption <= 125) {
3750
4043
  parameters = CIRCUIT_INFO["9-4-3-625"].parameter;
3751
4044
  if (proofSystem === "groth16" /* GROTH16 */) {
3752
4045
  if (circuitType === "0" /* IP1V */) {
@@ -3800,6 +4093,20 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3800
4093
  };
3801
4094
  }
3802
4095
  }
4096
+ function getAMaciRoundCircuitFee(maxVoter, maxOption) {
4097
+ let requiredFee = {
4098
+ denom: "peaka",
4099
+ amount: "0"
4100
+ };
4101
+ if (maxVoter <= 25 && maxOption <= 5) {
4102
+ requiredFee.amount = "50000000000000000000";
4103
+ } else if (maxVoter <= 625 && maxOption <= 25) {
4104
+ requiredFee.amount = "100000000000000000000";
4105
+ } else {
4106
+ throw new Error("Number of voters or options is too large.");
4107
+ }
4108
+ return requiredFee;
4109
+ }
3803
4110
 
3804
4111
  // src/libs/contract/contract.ts
3805
4112
  var Contract = class {
@@ -3840,26 +4147,32 @@ var Contract = class {
3840
4147
  wallet: signer,
3841
4148
  contractAddress: this.registryAddress
3842
4149
  });
4150
+ const requiredFee = getAMaciRoundCircuitFee(maxVoter, maxOption);
3843
4151
  preDeactivateRoot = preDeactivateRoot || "0";
3844
- const res = await client.createRound({
3845
- operator,
3846
- preDeactivateRoot,
3847
- voiceCreditAmount,
3848
- whitelist,
3849
- roundInfo: {
3850
- title,
3851
- description: description || "",
3852
- link: link || ""
3853
- },
3854
- votingTime: {
3855
- start_time,
3856
- end_time
4152
+ const res = await client.createRound(
4153
+ {
4154
+ operator,
4155
+ preDeactivateRoot,
4156
+ voiceCreditAmount,
4157
+ whitelist,
4158
+ roundInfo: {
4159
+ title,
4160
+ description: description || "",
4161
+ link: link || ""
4162
+ },
4163
+ votingTime: {
4164
+ start_time,
4165
+ end_time
4166
+ },
4167
+ maxVoter: maxVoter.toString(),
4168
+ maxOption: maxOption.toString(),
4169
+ certificationSystem: "0",
4170
+ circuitType
3857
4171
  },
3858
- maxVoter,
3859
- maxOption,
3860
- certificationSystem: "0",
3861
- circuitType
3862
- });
4172
+ "auto",
4173
+ void 0,
4174
+ [requiredFee]
4175
+ );
3863
4176
  let contractAddress = "";
3864
4177
  res.events.map((event) => {
3865
4178
  if (event.type === "wasm") {
@@ -3959,8 +4272,8 @@ var Contract = class {
3959
4272
  "2" /* ORACLE_MACI */,
3960
4273
  circuitType,
3961
4274
  "groth16" /* GROTH16 */,
3962
- "0",
3963
- "0"
4275
+ 0,
4276
+ 0
3964
4277
  );
3965
4278
  const instantiateResponse = await client.instantiate(
3966
4279
  address,
@@ -4071,6 +4384,16 @@ var OracleCertificate = class {
4071
4384
  const signatureData = await response.json();
4072
4385
  return signatureData;
4073
4386
  }
4387
+ async feegrantAllowance(granter, grantee) {
4388
+ const response = await this.http.fetchRest(
4389
+ `/cosmos/feegrant/v1beta1/allowance/${granter}/${grantee}`
4390
+ );
4391
+ return {
4392
+ granter,
4393
+ grantee,
4394
+ spend_limit: response.allowance.allowance.allowance.spend_limit
4395
+ };
4396
+ }
4074
4397
  };
4075
4398
 
4076
4399
  // src/libs/circom/index.ts
@@ -4404,6 +4727,24 @@ var MACI = class {
4404
4727
  }
4405
4728
  return response.data.signUpEvents[0].stateIdx;
4406
4729
  }
4730
+ async feegrantAllowance({
4731
+ address,
4732
+ contractAddress
4733
+ }) {
4734
+ try {
4735
+ const response = await this.oracleCertificate.feegrantAllowance(
4736
+ contractAddress,
4737
+ address
4738
+ );
4739
+ return response;
4740
+ } catch (error) {
4741
+ return {
4742
+ granter: contractAddress,
4743
+ grantee: address,
4744
+ spend_limit: []
4745
+ };
4746
+ }
4747
+ }
4407
4748
  // only for maci and oracle maci, amaci will set the voice credit when deploy the contract
4408
4749
  async queryWhitelistBalanceOf({
4409
4750
  signer,
@@ -4495,6 +4836,50 @@ var MACI = class {
4495
4836
  const circuitType = await this.getRoundCircuitType({ contractAddress });
4496
4837
  return circuitType === "1";
4497
4838
  }
4839
+ async queryRoundClaimable({
4840
+ contractAddress
4841
+ }) {
4842
+ try {
4843
+ const roundInfo = await this.getRoundInfo({ contractAddress });
4844
+ if (roundInfo.maciType !== "aMACI") {
4845
+ return {
4846
+ claimable: null,
4847
+ balance: null
4848
+ };
4849
+ }
4850
+ const votingEndTime = new Date(Number(roundInfo.votingEnd) / 10 ** 6);
4851
+ const currentTime = /* @__PURE__ */ new Date();
4852
+ const threeDaysInMs = 3 * 24 * 60 * 60 * 1e3;
4853
+ if (currentTime.getTime() - votingEndTime.getTime() <= threeDaysInMs) {
4854
+ return {
4855
+ claimable: null,
4856
+ balance: null
4857
+ };
4858
+ }
4859
+ const roundBalance = await this.indexer.balanceOf(contractAddress);
4860
+ if (isErrorResponse(roundBalance)) {
4861
+ throw new Error(
4862
+ `Failed to query round balance: ${roundBalance.error.type} ${roundBalance.error.message}`
4863
+ );
4864
+ }
4865
+ if (roundBalance.data.balance && roundBalance.data.balance !== "0" && roundBalance.data.balance !== "") {
4866
+ return {
4867
+ claimable: true,
4868
+ balance: roundBalance.data.balance
4869
+ };
4870
+ }
4871
+ return {
4872
+ claimable: false,
4873
+ balance: roundBalance.data.balance
4874
+ };
4875
+ } catch (error) {
4876
+ console.error("Error in queryRoundClaimable:", error);
4877
+ return {
4878
+ claimable: null,
4879
+ balance: null
4880
+ };
4881
+ }
4882
+ }
4498
4883
  async queryRoundGasStation({ contractAddress }) {
4499
4884
  const roundInfo = await this.getRoundInfo({ contractAddress });
4500
4885
  return roundInfo.gasStationEnable;