@dorafactory/maci-sdk 0.0.27 → 0.0.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dorafactory/maci-sdk",
3
- "version": "0.0.27",
3
+ "version": "0.0.28",
4
4
  "description": "SDK for interacting with maci",
5
5
  "keywords": [
6
6
  "maci",
@@ -43,7 +43,6 @@
43
43
  "@cosmjs/launchpad": "^0.27.1",
44
44
  "@cosmjs/proto-signing": "^0.32.1",
45
45
  "@cosmjs/stargate": "^0.32.1",
46
- "@dorafactory/circomlib": "^0.0.3",
47
46
  "assert": "^2.1.0",
48
47
  "bech32": "1.1.4",
49
48
  "blake-hash": "^2.0.0",
@@ -60,7 +59,8 @@
60
59
  "tmp": "^0.2.1",
61
60
  "ts-retry-promise": "^0.7.1",
62
61
  "tweetnacl": "^1.0.3",
63
- "valibot": "0.36.0"
62
+ "valibot": "0.36.0",
63
+ "@dorafactory/circomlib": "0.0.3"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@commitlint/cli": "^18.0.0",
package/src/libs/const.ts CHANGED
@@ -153,6 +153,7 @@ export interface NetworkConfig {
153
153
  oracleCodeId: number;
154
154
  oracleWhitelistBackendPubkey: string;
155
155
  oracleFeegrantOperator: string;
156
+ oracleCodeIds: string[];
156
157
  }
157
158
 
158
159
  export function getDefaultParams(
@@ -172,10 +173,11 @@ export function getDefaultParams(
172
173
  'dora1smg5qp5trjdkcekdjssqpjehdjf6n4cjss0clyvqcud3t3u3948s8rmgg4',
173
174
  maciCodeId: 106,
174
175
  // oracleCodeId: 116,// 9-4-3-625
175
- oracleCodeId: 117, // 6-3-3-125
176
+ oracleCodeId: 119, // 6-3-3-125
176
177
  oracleWhitelistBackendPubkey:
177
178
  'A61YtCv2ibMZmDeM02nEElil8wlHx1tLKogBk5dPgf/Q',
178
179
  oracleFeegrantOperator: 'dora16s9tljk8dy9ae335yvyzlm8gvkypx9228q8pq8',
180
+ oracleCodeIds: ['101', '116', '117', '119'],
179
181
  };
180
182
  case 'testnet':
181
183
  return {
@@ -190,10 +192,11 @@ export function getDefaultParams(
190
192
  'dora13c8aecstyxrhax9znvvh5zey89edrmd2k5va57pxvpe3fxtfsfeqlhsjnd',
191
193
  maciCodeId: 107,
192
194
  // oracleCodeId: 113, // 9-4-3-625
193
- oracleCodeId: 115, // 6-3-3-125
195
+ oracleCodeId: 123, // 6-3-3-125
194
196
  oracleWhitelistBackendPubkey:
195
197
  'AoYo/zENN/JquagPdG0/NMbWBBYxOM8BVN677mBXJKJQ',
196
198
  oracleFeegrantOperator: 'dora1xp0twdzsdeq4qg3c64v66552deax8zmvq4zw78',
199
+ oracleCodeIds: ['102', '105', '108', '110', '113', '115', '123'],
197
200
  };
198
201
  }
199
202
  }
@@ -15,4 +15,6 @@ export const ERROR = {
15
15
  ERROR_TRANSACTION_NOT_FOUND: 'ERROR_TRANSACTION_NOT_FOUND',
16
16
  ERROR_TRANSACTIONS_NOT_FOUND: 'ERROR_TRANSACTIONS_NOT_FOUND',
17
17
  ERROR_SIGN_UP_EVENTS_NOT_FOUND: 'ERROR_SIGN_UP_EVENTS_NOT_FOUND',
18
- };
18
+ ERROR_INVALID_FIELDS: 'ERROR_INVALID_FIELDS',
19
+ ERROR_CLAIM_INFOS_NOT_FOUND: 'ERROR_CLAIM_INFOS_NOT_FOUND',
20
+ } as const;
@@ -12,6 +12,7 @@ import {
12
12
  SignUpEventsResponse,
13
13
  OperatorDelayOperationsResponse,
14
14
  MissRateResponse,
15
+ SelectiveRoundResponse,
15
16
  } from '../../types';
16
17
  import { IndexerParams } from './types';
17
18
  import { Http } from '../http';
@@ -88,6 +89,20 @@ export class Indexer {
88
89
  return await this.round.getRoundById(id);
89
90
  }
90
91
 
92
+ /**
93
+ * @method getRoundWithFields
94
+ * @description Get a round by its address with selective fields.
95
+ * @param {string} address - The address of the round.
96
+ * @param {string[]} [fields] - The fields to retrieve.
97
+ * @returns {Promise<SelectiveRoundResponse>} The round response.
98
+ */
99
+ async getRoundWithFields(
100
+ address: string,
101
+ fields?: string[]
102
+ ): Promise<SelectiveRoundResponse> {
103
+ return await this.round.getRoundWithFields(address, fields);
104
+ }
105
+
91
106
  /**
92
107
  * @method getRounds
93
108
  * @description Get multiple rounds.
@@ -15,7 +15,7 @@ import {
15
15
  } from '@cosmjs/cosmwasm-stargate';
16
16
  import { GasPrice, calculateFee, StdFee } from '@cosmjs/stargate';
17
17
  import { MsgExecuteContract } from 'cosmjs-types/cosmwasm/wasm/v1/tx.js';
18
- import { CertificateEcosystem, ErrorResponse } from '../../types';
18
+ import { CertificateEcosystem, ErrorResponse, RoundType } from '../../types';
19
19
  import { SignatureResponse } from '../oracle-certificate/types';
20
20
  import { OracleWhitelistConfig } from '../contract/ts/OracleMaci.types';
21
21
  import { getAMaciRoundCircuitFee } from '../contract/utils';
@@ -130,6 +130,24 @@ export class MACI {
130
130
  }
131
131
  }
132
132
 
133
+ async hasFeegrant({
134
+ address,
135
+ contractAddress,
136
+ }: {
137
+ address: string;
138
+ contractAddress: string;
139
+ }): Promise<boolean> {
140
+ try {
141
+ const response = await this.oracleCertificate.feegrantAllowance(
142
+ contractAddress,
143
+ address
144
+ );
145
+ return response.spend_limit.length > 0;
146
+ } catch (error) {
147
+ return false;
148
+ }
149
+ }
150
+
133
151
  // only for maci and oracle maci, amaci will set the voice credit when deploy the contract
134
152
  async queryWhitelistBalanceOf({
135
153
  signer,
@@ -152,10 +170,16 @@ export class MACI {
152
170
  });
153
171
 
154
172
  if (isWhiteListed) {
155
- const round = await this.indexer.getRoundById(contractAddress);
173
+ const round = await this.indexer.getRoundWithFields(contractAddress, [
174
+ 'voiceCreditAmount',
175
+ ]);
156
176
 
157
177
  if (!isErrorResponse(round)) {
158
- return round.data.round.voiceCreditAmount;
178
+ if (round.data.round.voiceCreditAmount) {
179
+ return round.data.round.voiceCreditAmount;
180
+ } else {
181
+ return '0';
182
+ }
159
183
  } else {
160
184
  throw new Error(
161
185
  `Failed to query amaci voice credit: ${round.error.type} ${round.error.message}`
@@ -231,7 +255,7 @@ export class MACI {
231
255
  }
232
256
 
233
257
  async getRoundInfo({ contractAddress }: { contractAddress: string }) {
234
- const roundInfo = await this.indexer.getRoundById(contractAddress);
258
+ const roundInfo = await this.indexer.getRoundWithFields(contractAddress);
235
259
 
236
260
  if (isErrorResponse(roundInfo)) {
237
261
  throw new Error(
@@ -239,7 +263,7 @@ export class MACI {
239
263
  );
240
264
  }
241
265
 
242
- return roundInfo.data.round;
266
+ return roundInfo.data.round as RoundType;
243
267
  }
244
268
 
245
269
  async getRoundCircuitType({ contractAddress }: { contractAddress: string }) {
@@ -3,6 +3,8 @@ import {
3
3
  RoundResponse,
4
4
  RoundGraphqlResponse,
5
5
  RoundsGraphqlResponse,
6
+ SelectiveRoundResponse,
7
+ SelectiveRoundGraphqlResponse,
6
8
  } from '../../types';
7
9
  import { Http } from '../../libs';
8
10
  import { isValidAddress } from '../../utils';
@@ -135,6 +137,116 @@ export class Round {
135
137
  }
136
138
  }
137
139
 
140
+ /**
141
+ * Get round information with selective fields
142
+ * @param address Round address
143
+ * @param fields Array of fields to return, returns all fields if empty
144
+ * @returns Round information response
145
+ */
146
+ async getRoundWithFields(
147
+ address: string,
148
+ fields?: string[]
149
+ ): Promise<SelectiveRoundResponse> {
150
+ try {
151
+ if (!isValidAddress(address)) {
152
+ return {
153
+ code: 400,
154
+ error: {
155
+ message: 'Invalid round address format',
156
+ type: ERROR.ERROR_ROUND_INVALID_ADDRESS,
157
+ },
158
+ };
159
+ }
160
+
161
+ const defaultFields = [
162
+ 'id',
163
+ 'blockHeight',
164
+ 'txHash',
165
+ 'caller',
166
+ 'admin',
167
+ 'operator',
168
+ 'contractAddress',
169
+ 'circuitName',
170
+ 'timestamp',
171
+ 'votingStart',
172
+ 'votingEnd',
173
+ 'status',
174
+ 'period',
175
+ 'actionType',
176
+ 'roundTitle',
177
+ 'roundDescription',
178
+ 'roundLink',
179
+ 'coordinatorPubkeyX',
180
+ 'coordinatorPubkeyY',
181
+ 'voteOptionMap',
182
+ 'results',
183
+ 'allResult',
184
+ 'gasStationEnable',
185
+ 'totalGrant',
186
+ 'baseGrant',
187
+ 'totalBond',
188
+ 'circuitType',
189
+ 'circuitPower',
190
+ 'certificationSystem',
191
+ 'codeId',
192
+ 'maciType',
193
+ 'voiceCreditAmount',
194
+ 'preDeactivateRoot',
195
+ 'identity',
196
+ 'funds',
197
+ ];
198
+
199
+ if (fields && fields.length > 0) {
200
+ const invalidFields = fields.filter(
201
+ (field) => !defaultFields.includes(field)
202
+ );
203
+ if (invalidFields.length > 0) {
204
+ return {
205
+ code: 400,
206
+ error: {
207
+ message: `Invalid fields: ${invalidFields.join(', ')}`,
208
+ type: ERROR.ERROR_INVALID_FIELDS,
209
+ },
210
+ };
211
+ }
212
+ }
213
+
214
+ const selectedFields =
215
+ fields && fields.length > 0 ? fields : defaultFields;
216
+
217
+ const fieldString = selectedFields.join('\n ');
218
+
219
+ const ROUND_QUERY = `query {
220
+ round(id: "${address}") {
221
+ ${fieldString}
222
+ }
223
+ }`;
224
+
225
+ const response =
226
+ await this.http.fetchGraphql<SelectiveRoundGraphqlResponse>(
227
+ ROUND_QUERY,
228
+ ''
229
+ );
230
+
231
+ if (!response || !response.data || !response.data.round) {
232
+ return {
233
+ code: 404,
234
+ error: {
235
+ message: `No round data found for address ${address}`,
236
+ type: ERROR.ERROR_ROUND_NOT_FOUND,
237
+ },
238
+ };
239
+ }
240
+
241
+ return {
242
+ code: 200,
243
+ data: response.data,
244
+ };
245
+ } catch (error: any) {
246
+ return handleError(error as ErrorType);
247
+ }
248
+ }
249
+
138
250
  async getRounds(after: string, limit?: number): Promise<RoundsResponse> {
139
251
  try {
140
252
  const ROUND_HISTORY_QUERY = `query ($limit: Int, $after: Cursor) {
package/src/maci.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  TransactionsResponse,
11
11
  CircuitsResponse,
12
12
  ProofResponse,
13
+ SelectiveRoundResponse,
13
14
  } from './types';
14
15
  import {
15
16
  Http,
@@ -191,6 +192,20 @@ export class MaciClient {
191
192
  return await this.indexer.round.getRoundById(id);
192
193
  }
193
194
 
195
+ /**
196
+ * @method getRoundWithFields
197
+ * @description Get a round by its address with selective fields.
198
+ * @param {string} address - The address of the round.
199
+ * @param {string[]} [fields] - The fields to retrieve.
200
+ * @returns {Promise<SelectiveRoundResponse>} The round response.
201
+ */
202
+ async getRoundWithFields(
203
+ address: string,
204
+ fields?: string[]
205
+ ): Promise<SelectiveRoundResponse> {
206
+ return await this.indexer.round.getRoundWithFields(address, fields);
207
+ }
208
+
194
209
  /**
195
210
  * @method getRounds
196
211
  * @description Get multiple rounds.
@@ -93,6 +93,7 @@ export type RoundType = {
93
93
  voiceCreditAmount: string;
94
94
  preDeactivateRoot: string;
95
95
  identity: string;
96
+ funds: string;
96
97
  operatorLogoUrl?: string;
97
98
  operatorMoniker?: string;
98
99
  resultsList?: {
@@ -101,6 +102,8 @@ export type RoundType = {
101
102
  }[];
102
103
  };
103
104
 
105
+ export type SelectiveRoundType = Partial<RoundType>;
106
+
104
107
  export type ProofType = {
105
108
  nodes: {
106
109
  id: string;
@@ -355,6 +358,12 @@ export type RoundResponse =
355
358
  }>
356
359
  | ErrorResponse;
357
360
 
361
+ export type SelectiveRoundResponse =
362
+ | SuccessResponse<{
363
+ round: SelectiveRoundType;
364
+ }>
365
+ | ErrorResponse;
366
+
358
367
  export type RoundsResponse =
359
368
  | SuccessResponse<{
360
369
  rounds: {
@@ -377,6 +386,15 @@ export type RoundGraphqlResponse = {
377
386
  };
378
387
  };
379
388
 
389
+ /**
390
+ * GraphQL response type for selective round fields
391
+ */
392
+ export type SelectiveRoundGraphqlResponse = {
393
+ data: {
394
+ round: SelectiveRoundType;
395
+ };
396
+ };
397
+
380
398
  export type RoundsGraphqlResponse = {
381
399
  data: {
382
400
  rounds: {