@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.js CHANGED
@@ -256,11 +256,12 @@ var Http = class {
256
256
  );
257
257
  }
258
258
  }
259
- async fetchRest(path) {
259
+ async fetchRest(path, options) {
260
260
  try {
261
261
  const fetchFn = this.getFetch();
262
262
  const response = await fetchFn(`${this.restEndpoint}${path}`, {
263
- ...this.defaultOptions
263
+ ...this.defaultOptions,
264
+ ...options
264
265
  });
265
266
  if (!response.ok) {
266
267
  throw new HttpError(
@@ -291,6 +292,8 @@ var ERROR = {
291
292
  ERROR_CIRCUIT_NOT_FOUND: "ERROR_CIRCUIT_NOT_FOUND",
292
293
  ERROR_OPERATOR_INVALID_ADDRESS: "ERROR_OPERATOR_INVALID_ADDRESS",
293
294
  ERROR_OPERATOR_NOT_FOUND: "ERROR_OPERATOR_NOT_FOUND",
295
+ ERROR_OPERATOR_DELAY_HISTORY_NOT_FOUND: "ERROR_OPERATOR_DELAY_HISTORY_NOT_FOUND",
296
+ ERROR_QUERY_MISS_RATE_FAILED: "ERROR_QUERY_MISS_RATE_FAILED",
294
297
  ERROR_OPERATORS_NOT_FOUND: "ERROR_OPERATORS_NOT_FOUND",
295
298
  ERROR_PROOF_NOT_FOUND: "ERROR_PROOF_NOT_FOUND",
296
299
  ERROR_ROUND_INVALID_ADDRESS: "ERROR_ROUND_INVALID_ADDRESS",
@@ -717,6 +720,64 @@ var Operator = class {
717
720
  return handleError(error);
718
721
  }
719
722
  }
723
+ async getOperatorDelayOperationsByAddress(address, after, limit) {
724
+ try {
725
+ if (!isValidAddress(address)) {
726
+ return {
727
+ code: 400,
728
+ error: {
729
+ message: "Invalid operator address format",
730
+ type: ERROR.ERROR_OPERATOR_INVALID_ADDRESS
731
+ }
732
+ };
733
+ }
734
+ const OPERATORS_QUERY = `query ($limit: Int, $after: Cursor) {
735
+ operatorDelayOperations(first: $limit, after: $after, filter: {operatorAddress: {equalTo: "${address}"}}, orderBy: [TIMESTAMP_DESC]) {
736
+ pageInfo {
737
+ endCursor
738
+ hasNextPage
739
+ }
740
+ totalCount
741
+ edges {
742
+ cursor
743
+ node {
744
+ blockHeight
745
+ delayProcessDmsgCount
746
+ delayDuration
747
+ delayReason
748
+ delayType
749
+ id
750
+ nodeId
751
+ operatorAddress
752
+ timestamp
753
+ roundAddress
754
+ }
755
+ }
756
+ }
757
+ }`;
758
+ const response = await this.http.fetchGraphql(
759
+ OPERATORS_QUERY,
760
+ after,
761
+ limit
762
+ );
763
+ if (!response || !response.data || !response.data.operatorDelayOperations || !response.data.operatorDelayOperations.edges || response.data.operatorDelayOperations.edges.length === 0) {
764
+ return {
765
+ code: 404,
766
+ error: {
767
+ message: `No operatorDelayOperations found for address ${address}`,
768
+ type: ERROR.ERROR_OPERATOR_DELAY_HISTORY_NOT_FOUND
769
+ }
770
+ };
771
+ }
772
+ const operator = {
773
+ code: 200,
774
+ data: response.data
775
+ };
776
+ return operator;
777
+ } catch (error) {
778
+ return handleError(error);
779
+ }
780
+ }
720
781
  async getOperators(after, limit) {
721
782
  try {
722
783
  const OPERATORS_QUERY = `query ($limit: Int, $after: Cursor) {
@@ -820,6 +881,228 @@ var Operator = class {
820
881
  return handleError(error);
821
882
  }
822
883
  }
884
+ async queryMissRate(address, durationDay) {
885
+ try {
886
+ const now = /* @__PURE__ */ new Date();
887
+ const startTime = new Date(
888
+ now.getTime() - durationDay * 24 * 60 * 60 * 1e3
889
+ );
890
+ const startTimestamp = Math.floor(startTime.getTime() / 1e3);
891
+ const endNanosTimestamp = Math.floor(startTime.getTime() * 1e6);
892
+ const txTimestamp = Math.floor(startTime.getTime());
893
+ const QUERY = `query ($limit: Int, $after: Cursor) {
894
+ operatorDelayOperations(
895
+ first: $limit,
896
+ after: $after,
897
+ filter: {
898
+ operatorAddress: {equalTo: "${address}"},
899
+ timestamp: { greaterThanOrEqualTo: "${startTimestamp}" }
900
+ },
901
+ orderBy: [TIMESTAMP_DESC]
902
+ ) {
903
+ edges {
904
+ node {
905
+ blockHeight
906
+ delayProcessDmsgCount
907
+ delayDuration
908
+ delayReason
909
+ delayType
910
+ id
911
+ nodeId
912
+ operatorAddress
913
+ timestamp
914
+ roundAddress
915
+ }
916
+ }
917
+ }
918
+ }`;
919
+ const ROUNDS_QUERY = `query ($limit: Int, $after: Cursor) {
920
+ rounds(first: $limit, after: $after,
921
+ filter: {
922
+ operator: {equalTo: "${address}"},
923
+ votingEnd: { greaterThanOrEqualTo: "${endNanosTimestamp}" }
924
+ },
925
+ orderBy: [TIMESTAMP_DESC]
926
+ ){
927
+ pageInfo {
928
+ endCursor
929
+ hasNextPage
930
+ }
931
+ totalCount
932
+ edges {
933
+ node {
934
+ id
935
+ blockHeight
936
+ txHash
937
+ caller
938
+ admin
939
+ operator
940
+ contractAddress
941
+ circuitName
942
+ timestamp
943
+ votingStart
944
+ votingEnd
945
+ status
946
+ period
947
+ actionType
948
+ roundTitle
949
+ roundDescription
950
+ roundLink
951
+ coordinatorPubkeyX
952
+ coordinatorPubkeyY
953
+ voteOptionMap
954
+ results
955
+ allResult
956
+ gasStationEnable
957
+ totalGrant
958
+ baseGrant
959
+ totalBond
960
+ circuitType
961
+ circuitPower
962
+ certificationSystem
963
+ codeId
964
+ maciType
965
+ voiceCreditAmount
966
+ preDeactivateRoot
967
+ }
968
+ cursor
969
+ }
970
+ }
971
+ }
972
+ `;
973
+ const roundsResponse = await this.http.fetchGraphql(
974
+ ROUNDS_QUERY,
975
+ "",
976
+ 9999
977
+ );
978
+ const roundContractAddresses = roundsResponse?.data?.rounds?.edges?.map(
979
+ (edge) => edge.node.contractAddress
980
+ ) || [];
981
+ const TRANSACTIONS_QUERY = `query transactions($limit: Int, $after: Cursor) {
982
+ transactions(first: $limit, after: $after,
983
+ filter: {
984
+ timestamp: { greaterThanOrEqualTo: "${txTimestamp}" },
985
+ type: { equalTo: "op:procDeactivate" },
986
+ contractAddress: { in: ${JSON.stringify(roundContractAddresses)} }
987
+ },
988
+ orderBy: [TIMESTAMP_DESC]
989
+ ){
990
+ pageInfo {
991
+ endCursor
992
+ hasNextPage
993
+ }
994
+ totalCount
995
+ edges {
996
+ cursor
997
+ node {
998
+ id
999
+ blockHeight
1000
+ txHash
1001
+ timestamp
1002
+ type
1003
+ status
1004
+ circuitName
1005
+ fee
1006
+ gasUsed
1007
+ gasWanted
1008
+ caller
1009
+ contractAddress
1010
+ }
1011
+ }
1012
+ }
1013
+ }`;
1014
+ const [delayResponse, transactionsResponse] = await Promise.all([
1015
+ this.http.fetchGraphql(
1016
+ QUERY,
1017
+ "",
1018
+ 9999
1019
+ ),
1020
+ this.http.fetchGraphql(
1021
+ TRANSACTIONS_QUERY,
1022
+ "",
1023
+ 9999
1024
+ )
1025
+ ]);
1026
+ const dailyStats = /* @__PURE__ */ new Map();
1027
+ const endDate = /* @__PURE__ */ new Date();
1028
+ for (let i = 0; i < durationDay; i++) {
1029
+ const date = new Date(endDate.getTime() - i * 24 * 60 * 60 * 1e3).toISOString().split("T")[0];
1030
+ dailyStats.set(date, {
1031
+ delayCount: 0,
1032
+ deactivateDelay: {
1033
+ count: 0,
1034
+ dmsgCount: 0
1035
+ },
1036
+ tallyDelay: {
1037
+ count: 0
1038
+ },
1039
+ totalDelayDuration: 0,
1040
+ avgDelayDuration: 0,
1041
+ tallyCount: 0,
1042
+ deactivateCount: 0,
1043
+ missRate: 0
1044
+ });
1045
+ }
1046
+ delayResponse.data.operatorDelayOperations.edges.forEach(({ node }) => {
1047
+ const date = new Date(parseInt(node.timestamp) * 1e3).toISOString().split("T")[0];
1048
+ if (dailyStats.has(date)) {
1049
+ const stats = dailyStats.get(date);
1050
+ stats.delayCount++;
1051
+ stats.totalDelayDuration += parseInt(node.delayDuration);
1052
+ if (node.delayType === "deactivate_delay") {
1053
+ stats.deactivateDelay.count++;
1054
+ stats.deactivateDelay.dmsgCount += node.delayProcessDmsgCount;
1055
+ } else if (node.delayType === "tally_delay") {
1056
+ stats.tallyDelay.count++;
1057
+ }
1058
+ }
1059
+ });
1060
+ if (roundsResponse?.data?.rounds?.edges) {
1061
+ roundsResponse.data.rounds.edges.forEach(({ node }) => {
1062
+ const date = new Date(parseInt(node.votingEnd) / 1e6).toISOString().split("T")[0];
1063
+ if (dailyStats.has(date)) {
1064
+ const stats = dailyStats.get(date);
1065
+ stats.tallyCount++;
1066
+ }
1067
+ });
1068
+ }
1069
+ if (transactionsResponse?.data?.transactions?.edges) {
1070
+ transactionsResponse.data.transactions.edges.forEach(({ node }) => {
1071
+ const date = new Date(parseInt(node.timestamp)).toISOString().split("T")[0];
1072
+ if (dailyStats.has(date)) {
1073
+ const stats = dailyStats.get(date);
1074
+ stats.deactivateCount++;
1075
+ }
1076
+ });
1077
+ }
1078
+ return {
1079
+ code: 200,
1080
+ data: {
1081
+ missRate: Array.from(dailyStats.entries()).map(([date, stats]) => ({
1082
+ date,
1083
+ delayCount: stats.delayCount,
1084
+ deactivateDelay: stats.deactivateDelay,
1085
+ tallyDelay: stats.tallyDelay,
1086
+ totalDelayDuration: stats.totalDelayDuration,
1087
+ avgDelayDuration: stats.delayCount > 0 ? stats.totalDelayDuration / stats.delayCount : 0,
1088
+ tallyCount: stats.tallyCount,
1089
+ deactivateCount: stats.deactivateCount,
1090
+ missRate: stats.deactivateCount + stats.tallyCount > 0 ? parseFloat(
1091
+ ((stats.deactivateDelay.count + stats.tallyDelay.count) / (stats.deactivateCount + stats.tallyCount)).toFixed(2)
1092
+ ) : 0
1093
+ })).sort((a, b) => b.date.localeCompare(a.date))
1094
+ }
1095
+ };
1096
+ } catch (error) {
1097
+ return {
1098
+ code: 404,
1099
+ error: {
1100
+ message: "Query miss rate failed",
1101
+ type: ERROR.ERROR_QUERY_MISS_RATE_FAILED
1102
+ }
1103
+ };
1104
+ }
1105
+ }
823
1106
  };
824
1107
 
825
1108
  // src/libs/query/round.ts
@@ -1647,6 +1930,16 @@ var Indexer = class {
1647
1930
  async getOperatorByAddress(address) {
1648
1931
  return await this.operator.getOperatorByAddress(address);
1649
1932
  }
1933
+ async getOperatorDelayOperationsByAddress(address, after, limit) {
1934
+ return await this.operator.getOperatorDelayOperationsByAddress(
1935
+ address,
1936
+ after,
1937
+ limit
1938
+ );
1939
+ }
1940
+ async queryMissRate(address, durationDay) {
1941
+ return await this.operator.queryMissRate(address, durationDay);
1942
+ }
1650
1943
  /**
1651
1944
  * @method getOperators
1652
1945
  * @description Get multiple operators.
@@ -3783,7 +4076,7 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3783
4076
  `Invalid proof system ${proofSystem}, only support GROTH16 and PLONK`
3784
4077
  );
3785
4078
  }
3786
- if (Number(maxVoter) <= 25 && Number(maxOption) <= 5) {
4079
+ if (maxVoter <= 25 && maxOption <= 5) {
3787
4080
  parameters = CIRCUIT_INFO["2-1-1-5"].parameter;
3788
4081
  if (proofSystem === "groth16" /* GROTH16 */) {
3789
4082
  groth16ProcessVkey = CIRCUIT_INFO["2-1-1-5"]["groth16"].process_vkey;
@@ -3792,7 +4085,7 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3792
4085
  plonkProcessVkey = CIRCUIT_INFO["2-1-1-5"]["plonk"]?.process_vkey;
3793
4086
  plonkTallyVkey = CIRCUIT_INFO["2-1-1-5"]["plonk"]?.tally_vkey;
3794
4087
  }
3795
- } else if (Number(maxVoter) <= 625 && Number(maxOption) <= 25) {
4088
+ } else if (maxVoter <= 625 && maxOption <= 25) {
3796
4089
  parameters = CIRCUIT_INFO["4-2-2-25"].parameter;
3797
4090
  if (proofSystem === "groth16" /* GROTH16 */) {
3798
4091
  groth16ProcessVkey = CIRCUIT_INFO["4-2-2-25"]["groth16"].process_vkey;
@@ -3801,7 +4094,7 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3801
4094
  plonkProcessVkey = CIRCUIT_INFO["4-2-2-25"]["plonk"]?.process_vkey;
3802
4095
  plonkTallyVkey = CIRCUIT_INFO["4-2-2-25"]["plonk"]?.tally_vkey;
3803
4096
  }
3804
- } else if (Number(maxVoter) <= 15625 && Number(maxOption) <= 125) {
4097
+ } else if (maxVoter <= 15625 && maxOption <= 125) {
3805
4098
  parameters = CIRCUIT_INFO["6-3-3-125"].parameter;
3806
4099
  if (proofSystem === "groth16" /* GROTH16 */) {
3807
4100
  groth16ProcessVkey = CIRCUIT_INFO["6-3-3-125"]["groth16"].process_vkey;
@@ -3810,7 +4103,7 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3810
4103
  plonkProcessVkey = CIRCUIT_INFO["6-3-3-125"]["plonk"]?.process_vkey;
3811
4104
  plonkTallyVkey = CIRCUIT_INFO["6-3-3-125"]["plonk"]?.tally_vkey;
3812
4105
  }
3813
- } else if (Number(maxVoter) <= 1953125 && Number(maxOption) <= 125) {
4106
+ } else if (maxVoter <= 1953125 && maxOption <= 125) {
3814
4107
  parameters = CIRCUIT_INFO["9-4-3-625"].parameter;
3815
4108
  if (proofSystem === "groth16" /* GROTH16 */) {
3816
4109
  if (circuitType === "0" /* IP1V */) {
@@ -3864,6 +4157,20 @@ function getContractParams(type, circuitType, proofSystem, maxVoter, maxOption)
3864
4157
  };
3865
4158
  }
3866
4159
  }
4160
+ function getAMaciRoundCircuitFee(maxVoter, maxOption) {
4161
+ let requiredFee = {
4162
+ denom: "peaka",
4163
+ amount: "0"
4164
+ };
4165
+ if (maxVoter <= 25 && maxOption <= 5) {
4166
+ requiredFee.amount = "50000000000000000000";
4167
+ } else if (maxVoter <= 625 && maxOption <= 25) {
4168
+ requiredFee.amount = "100000000000000000000";
4169
+ } else {
4170
+ throw new Error("Number of voters or options is too large.");
4171
+ }
4172
+ return requiredFee;
4173
+ }
3867
4174
 
3868
4175
  // src/libs/contract/contract.ts
3869
4176
  var Contract = class {
@@ -3904,26 +4211,32 @@ var Contract = class {
3904
4211
  wallet: signer,
3905
4212
  contractAddress: this.registryAddress
3906
4213
  });
4214
+ const requiredFee = getAMaciRoundCircuitFee(maxVoter, maxOption);
3907
4215
  preDeactivateRoot = preDeactivateRoot || "0";
3908
- const res = await client.createRound({
3909
- operator,
3910
- preDeactivateRoot,
3911
- voiceCreditAmount,
3912
- whitelist,
3913
- roundInfo: {
3914
- title,
3915
- description: description || "",
3916
- link: link || ""
3917
- },
3918
- votingTime: {
3919
- start_time,
3920
- end_time
4216
+ const res = await client.createRound(
4217
+ {
4218
+ operator,
4219
+ preDeactivateRoot,
4220
+ voiceCreditAmount,
4221
+ whitelist,
4222
+ roundInfo: {
4223
+ title,
4224
+ description: description || "",
4225
+ link: link || ""
4226
+ },
4227
+ votingTime: {
4228
+ start_time,
4229
+ end_time
4230
+ },
4231
+ maxVoter: maxVoter.toString(),
4232
+ maxOption: maxOption.toString(),
4233
+ certificationSystem: "0",
4234
+ circuitType
3921
4235
  },
3922
- maxVoter,
3923
- maxOption,
3924
- certificationSystem: "0",
3925
- circuitType
3926
- });
4236
+ "auto",
4237
+ void 0,
4238
+ [requiredFee]
4239
+ );
3927
4240
  let contractAddress = "";
3928
4241
  res.events.map((event) => {
3929
4242
  if (event.type === "wasm") {
@@ -4023,8 +4336,8 @@ var Contract = class {
4023
4336
  "2" /* ORACLE_MACI */,
4024
4337
  circuitType,
4025
4338
  "groth16" /* GROTH16 */,
4026
- "0",
4027
- "0"
4339
+ 0,
4340
+ 0
4028
4341
  );
4029
4342
  const instantiateResponse = await client.instantiate(
4030
4343
  address,
@@ -4135,6 +4448,16 @@ var OracleCertificate = class {
4135
4448
  const signatureData = await response.json();
4136
4449
  return signatureData;
4137
4450
  }
4451
+ async feegrantAllowance(granter, grantee) {
4452
+ const response = await this.http.fetchRest(
4453
+ `/cosmos/feegrant/v1beta1/allowance/${granter}/${grantee}`
4454
+ );
4455
+ return {
4456
+ granter,
4457
+ grantee,
4458
+ spend_limit: response.allowance.allowance.allowance.spend_limit
4459
+ };
4460
+ }
4138
4461
  };
4139
4462
 
4140
4463
  // src/libs/circom/index.ts
@@ -4460,6 +4783,24 @@ var MACI = class {
4460
4783
  }
4461
4784
  return response.data.signUpEvents[0].stateIdx;
4462
4785
  }
4786
+ async feegrantAllowance({
4787
+ address,
4788
+ contractAddress
4789
+ }) {
4790
+ try {
4791
+ const response = await this.oracleCertificate.feegrantAllowance(
4792
+ contractAddress,
4793
+ address
4794
+ );
4795
+ return response;
4796
+ } catch (error) {
4797
+ return {
4798
+ granter: contractAddress,
4799
+ grantee: address,
4800
+ spend_limit: []
4801
+ };
4802
+ }
4803
+ }
4463
4804
  // only for maci and oracle maci, amaci will set the voice credit when deploy the contract
4464
4805
  async queryWhitelistBalanceOf({
4465
4806
  signer,
@@ -4551,6 +4892,50 @@ var MACI = class {
4551
4892
  const circuitType = await this.getRoundCircuitType({ contractAddress });
4552
4893
  return circuitType === "1";
4553
4894
  }
4895
+ async queryRoundClaimable({
4896
+ contractAddress
4897
+ }) {
4898
+ try {
4899
+ const roundInfo = await this.getRoundInfo({ contractAddress });
4900
+ if (roundInfo.maciType !== "aMACI") {
4901
+ return {
4902
+ claimable: null,
4903
+ balance: null
4904
+ };
4905
+ }
4906
+ const votingEndTime = new Date(Number(roundInfo.votingEnd) / 10 ** 6);
4907
+ const currentTime = /* @__PURE__ */ new Date();
4908
+ const threeDaysInMs = 3 * 24 * 60 * 60 * 1e3;
4909
+ if (currentTime.getTime() - votingEndTime.getTime() <= threeDaysInMs) {
4910
+ return {
4911
+ claimable: null,
4912
+ balance: null
4913
+ };
4914
+ }
4915
+ const roundBalance = await this.indexer.balanceOf(contractAddress);
4916
+ if (isErrorResponse(roundBalance)) {
4917
+ throw new Error(
4918
+ `Failed to query round balance: ${roundBalance.error.type} ${roundBalance.error.message}`
4919
+ );
4920
+ }
4921
+ if (roundBalance.data.balance && roundBalance.data.balance !== "0" && roundBalance.data.balance !== "") {
4922
+ return {
4923
+ claimable: true,
4924
+ balance: roundBalance.data.balance
4925
+ };
4926
+ }
4927
+ return {
4928
+ claimable: false,
4929
+ balance: roundBalance.data.balance
4930
+ };
4931
+ } catch (error) {
4932
+ console.error("Error in queryRoundClaimable:", error);
4933
+ return {
4934
+ claimable: null,
4935
+ balance: null
4936
+ };
4937
+ }
4938
+ }
4554
4939
  async queryRoundGasStation({ contractAddress }) {
4555
4940
  const roundInfo = await this.getRoundInfo({ contractAddress });
4556
4941
  return roundInfo.gasStationEnable;