@dorafactory/maci-sdk 0.1.0 → 0.1.2-pre.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,16 +6,19 @@ import {
6
6
  createMaciClientBy,
7
7
  createOracleMaciClientBy,
8
8
  createRegistryClientBy,
9
+ createSaasClientBy,
9
10
  } from './config';
10
11
  import {
11
12
  CreateAMaciRoundParams,
12
13
  CreateMaciRoundParams,
13
14
  CreateOracleMaciRoundParams,
15
+ CreateSaasOracleMaciRoundParams,
14
16
  } from './types';
15
17
  import { getAMaciRoundCircuitFee, getContractParams } from './utils';
16
18
  import { QTR_LIB } from './vars';
17
19
  import { MaciRoundType, MaciCertSystemType } from '../../types';
18
20
  import { unpackPubKey } from '../crypto';
21
+ import { StdFee, GasPrice, calculateFee } from '@cosmjs/stargate';
19
22
 
20
23
  export const prefix = 'dora';
21
24
 
@@ -23,8 +26,10 @@ export class Contract {
23
26
  public network: 'mainnet' | 'testnet';
24
27
  public rpcEndpoint: string;
25
28
  public registryAddress: string;
29
+ public saasAddress: string;
26
30
  public maciCodeId: number;
27
31
  public oracleCodeId: number;
32
+ public saasOracleCodeId: number;
28
33
  public feegrantOperator: string;
29
34
  public whitelistBackendPubkey: string;
30
35
 
@@ -32,16 +37,20 @@ export class Contract {
32
37
  network,
33
38
  rpcEndpoint,
34
39
  registryAddress,
40
+ saasAddress,
35
41
  maciCodeId,
36
42
  oracleCodeId,
43
+ saasOracleCodeId,
37
44
  feegrantOperator,
38
45
  whitelistBackendPubkey,
39
46
  }: ContractParams) {
40
47
  this.network = network;
41
48
  this.rpcEndpoint = rpcEndpoint;
42
49
  this.registryAddress = registryAddress;
50
+ this.saasAddress = saasAddress;
43
51
  this.maciCodeId = maciCodeId;
44
52
  this.oracleCodeId = oracleCodeId;
53
+ this.saasOracleCodeId = saasOracleCodeId;
45
54
  this.feegrantOperator = feegrantOperator;
46
55
  this.whitelistBackendPubkey = whitelistBackendPubkey;
47
56
  }
@@ -197,11 +206,14 @@ export class Contract {
197
206
  title,
198
207
  description,
199
208
  link,
209
+ maxVoter,
200
210
  voteOptionMap,
201
211
  circuitType,
202
212
  whitelistEcosystem,
203
213
  whitelistSnapshotHeight,
204
214
  whitelistVotingPowerArgs,
215
+ whitelistBackendPubkey,
216
+ feegrantOperator,
205
217
  fee = 'auto',
206
218
  }: CreateOracleMaciRoundParams & { signer: OfflineSigner }) {
207
219
  const start_time = (startVoting.getTime() * 1_000_000).toString();
@@ -223,6 +235,7 @@ export class Contract {
223
235
  address,
224
236
  this.oracleCodeId,
225
237
  {
238
+ max_voters: maxVoter.toString(),
226
239
  round_info: { title, description: description || '', link: link || '' },
227
240
  voting_time: {
228
241
  start_time,
@@ -233,13 +246,17 @@ export class Contract {
233
246
  y: operatorPubkeyY.toString(),
234
247
  },
235
248
  vote_option_map: voteOptionMap,
236
- whitelist_backend_pubkey: this.whitelistBackendPubkey,
249
+ whitelist_backend_pubkey: whitelistBackendPubkey
250
+ ? whitelistBackendPubkey
251
+ : this.whitelistBackendPubkey,
237
252
  whitelist_ecosystem: whitelistEcosystem,
238
253
  whitelist_snapshot_height: whitelistSnapshotHeight,
239
254
  whitelist_voting_power_args: whitelistVotingPowerArgs,
240
255
  circuit_type: maciVoteType,
241
256
  certification_system: maciCertSystem,
242
- feegrant_operator: this.feegrantOperator,
257
+ feegrant_operator: feegrantOperator
258
+ ? feegrantOperator
259
+ : this.feegrantOperator,
243
260
  },
244
261
  `[Oracle MACI] ${title}`,
245
262
  fee
@@ -248,6 +265,526 @@ export class Contract {
248
265
  return instantiateResponse;
249
266
  }
250
267
 
268
+ async createSaasOracleMaciRound({
269
+ signer,
270
+ operatorPubkey,
271
+ startVoting,
272
+ endVoting,
273
+ title,
274
+ description,
275
+ link,
276
+ maxVoter,
277
+ voteOptionMap,
278
+ whitelistBackendPubkey,
279
+ }: CreateSaasOracleMaciRoundParams & { signer: OfflineSigner }) {
280
+ const startTime = (startVoting.getTime() * 1_000_000).toString();
281
+ const endTime = (endVoting.getTime() * 1_000_000).toString();
282
+
283
+ const client = await createSaasClientBy({
284
+ rpcEndpoint: this.rpcEndpoint,
285
+ wallet: signer,
286
+ contractAddress: this.saasAddress,
287
+ });
288
+ const [operatorPubkeyX, operatorPubkeyY] = unpackPubKey(
289
+ BigInt(operatorPubkey)
290
+ );
291
+
292
+ const createResponse = await client.createOracleMaciRound({
293
+ certificationSystem: '0',
294
+ circuitType: '0',
295
+ coordinator: {
296
+ x: operatorPubkeyX.toString(),
297
+ y: operatorPubkeyY.toString(),
298
+ },
299
+ maxVoters: maxVoter,
300
+ roundInfo: {
301
+ title,
302
+ description: description || '',
303
+ link: link || '',
304
+ },
305
+ startTime,
306
+ endTime,
307
+ voteOptionMap,
308
+ whitelistBackendPubkey:
309
+ whitelistBackendPubkey || this.whitelistBackendPubkey,
310
+ });
311
+
312
+ let contractAddress = '';
313
+ createResponse.events.map((event) => {
314
+ if (event.type === 'wasm') {
315
+ let actionEvent = event.attributes.find(
316
+ (attr) => attr.key === 'action'
317
+ )!;
318
+ if (actionEvent.value === 'created_oracle_maci_round') {
319
+ contractAddress = event.attributes
320
+ .find((attr) => attr.key === 'round_addr')!
321
+ .value.toString();
322
+ }
323
+ }
324
+ });
325
+ return {
326
+ ...createResponse,
327
+ contractAddress,
328
+ };
329
+ }
330
+
331
+ async setSaasOracleMaciRoundInfo({
332
+ signer,
333
+ contractAddress,
334
+ title,
335
+ description,
336
+ link,
337
+ gasStation = false,
338
+ fee = 1.8,
339
+ }: {
340
+ signer: OfflineSigner;
341
+ contractAddress: string;
342
+ title: string;
343
+ description: string;
344
+ link: string;
345
+ gasStation?: boolean;
346
+ fee?: StdFee | 'auto' | number;
347
+ }) {
348
+ const client = await createSaasClientBy({
349
+ rpcEndpoint: this.rpcEndpoint,
350
+ wallet: signer,
351
+ contractAddress: this.saasAddress,
352
+ });
353
+
354
+ const roundInfo = {
355
+ title,
356
+ description,
357
+ link,
358
+ };
359
+
360
+ if (gasStation && typeof fee !== 'object') {
361
+ // When gasStation is true and fee is not StdFee, we need to simulate first then add granter
362
+ const [{ address }] = await signer.getAccounts();
363
+ const contractClient = await this.contractClient({ signer });
364
+ const msg = {
365
+ set_round_info: {
366
+ contract_addr: contractAddress,
367
+ round_info: roundInfo,
368
+ },
369
+ };
370
+ const gasEstimation = await contractClient.simulate(
371
+ address,
372
+ [
373
+ {
374
+ typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
375
+ value: {
376
+ sender: address,
377
+ contract: this.saasAddress,
378
+ msg: new TextEncoder().encode(JSON.stringify(msg)),
379
+ },
380
+ },
381
+ ],
382
+ ''
383
+ );
384
+ const multiplier = typeof fee === 'number' ? fee : 1.8;
385
+ const gasPrice = GasPrice.fromString('10000000000peaka');
386
+ const calculatedFee = calculateFee(
387
+ Math.round(gasEstimation * multiplier),
388
+ gasPrice
389
+ );
390
+ const grantFee: StdFee = {
391
+ amount: calculatedFee.amount,
392
+ gas: calculatedFee.gas,
393
+ granter: this.saasAddress,
394
+ };
395
+ return client.setRoundInfo(
396
+ {
397
+ contractAddr: contractAddress,
398
+ roundInfo,
399
+ },
400
+ grantFee
401
+ );
402
+ } else if (gasStation && typeof fee === 'object') {
403
+ // When gasStation is true and fee is StdFee, add granter
404
+ const grantFee: StdFee = {
405
+ ...fee,
406
+ granter: this.saasAddress,
407
+ };
408
+ return client.setRoundInfo(
409
+ {
410
+ contractAddr: contractAddress,
411
+ roundInfo,
412
+ },
413
+ grantFee
414
+ );
415
+ }
416
+
417
+ return client.setRoundInfo(
418
+ {
419
+ contractAddr: contractAddress,
420
+ roundInfo,
421
+ },
422
+ fee
423
+ );
424
+ }
425
+
426
+ async setSaasOracleMaciRoundVoteOptions({
427
+ signer,
428
+ contractAddress,
429
+ voteOptionMap,
430
+ gasStation = false,
431
+ fee = 1.8,
432
+ }: {
433
+ signer: OfflineSigner;
434
+ contractAddress: string;
435
+ voteOptionMap: string[];
436
+ gasStation?: boolean;
437
+ fee?: StdFee | 'auto' | number;
438
+ }) {
439
+ const client = await createSaasClientBy({
440
+ rpcEndpoint: this.rpcEndpoint,
441
+ wallet: signer,
442
+ contractAddress: this.saasAddress,
443
+ });
444
+
445
+ if (gasStation && typeof fee !== 'object') {
446
+ // When gasStation is true and fee is not StdFee, we need to simulate first then add granter
447
+ const [{ address }] = await signer.getAccounts();
448
+ const contractClient = await this.contractClient({ signer });
449
+ const msg = {
450
+ set_vote_options_map: {
451
+ contract_addr: contractAddress,
452
+ vote_option_map: voteOptionMap,
453
+ },
454
+ };
455
+ const gasEstimation = await contractClient.simulate(
456
+ address,
457
+ [
458
+ {
459
+ typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
460
+ value: {
461
+ sender: address,
462
+ contract: this.saasAddress,
463
+ msg: new TextEncoder().encode(JSON.stringify(msg)),
464
+ },
465
+ },
466
+ ],
467
+ ''
468
+ );
469
+ const multiplier = typeof fee === 'number' ? fee : 1.8;
470
+ const gasPrice = GasPrice.fromString('10000000000peaka');
471
+ const calculatedFee = calculateFee(
472
+ Math.round(gasEstimation * multiplier),
473
+ gasPrice
474
+ );
475
+ const grantFee: StdFee = {
476
+ amount: calculatedFee.amount,
477
+ gas: calculatedFee.gas,
478
+ granter: this.saasAddress,
479
+ };
480
+ return client.setVoteOptionsMap(
481
+ {
482
+ contractAddr: contractAddress,
483
+ voteOptionMap,
484
+ },
485
+ grantFee
486
+ );
487
+ } else if (gasStation && typeof fee === 'object') {
488
+ // When gasStation is true and fee is StdFee, add granter
489
+ const grantFee: StdFee = {
490
+ ...fee,
491
+ granter: this.saasAddress,
492
+ };
493
+ return client.setVoteOptionsMap(
494
+ {
495
+ contractAddr: contractAddress,
496
+ voteOptionMap,
497
+ },
498
+ grantFee
499
+ );
500
+ }
501
+
502
+ return client.setVoteOptionsMap(
503
+ {
504
+ contractAddr: contractAddress,
505
+ voteOptionMap,
506
+ },
507
+ fee
508
+ );
509
+ }
510
+
511
+ async addSaasOperator({
512
+ signer,
513
+ operator,
514
+ gasStation = false,
515
+ fee = 1.8,
516
+ }: {
517
+ signer: OfflineSigner;
518
+ operator: string;
519
+ gasStation?: boolean;
520
+ fee?: StdFee | 'auto' | number;
521
+ }) {
522
+ const client = await createSaasClientBy({
523
+ rpcEndpoint: this.rpcEndpoint,
524
+ wallet: signer,
525
+ contractAddress: this.saasAddress,
526
+ });
527
+
528
+ if (gasStation && typeof fee !== 'object') {
529
+ // When gasStation is true and fee is not StdFee, we need to simulate first then add granter
530
+ const [{ address }] = await signer.getAccounts();
531
+ const contractClient = await this.contractClient({ signer });
532
+ const msg = {
533
+ add_operator: {
534
+ operator,
535
+ },
536
+ };
537
+ const gasEstimation = await contractClient.simulate(
538
+ address,
539
+ [
540
+ {
541
+ typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
542
+ value: {
543
+ sender: address,
544
+ contract: this.saasAddress,
545
+ msg: new TextEncoder().encode(JSON.stringify(msg)),
546
+ },
547
+ },
548
+ ],
549
+ ''
550
+ );
551
+ const multiplier = typeof fee === 'number' ? fee : 1.8;
552
+ const gasPrice = GasPrice.fromString('10000000000peaka');
553
+ const calculatedFee = calculateFee(
554
+ Math.round(gasEstimation * multiplier),
555
+ gasPrice
556
+ );
557
+ const grantFee: StdFee = {
558
+ amount: calculatedFee.amount,
559
+ gas: calculatedFee.gas,
560
+ granter: this.saasAddress,
561
+ };
562
+ return client.addOperator({ operator }, grantFee);
563
+ } else if (gasStation && typeof fee === 'object') {
564
+ // When gasStation is true and fee is StdFee, add granter
565
+ const grantFee: StdFee = {
566
+ ...fee,
567
+ granter: this.saasAddress,
568
+ };
569
+ return client.addOperator({ operator }, grantFee);
570
+ }
571
+
572
+ return client.addOperator({ operator }, fee);
573
+ }
574
+
575
+ async removeSaasOperator({
576
+ signer,
577
+ operator,
578
+ gasStation = false,
579
+ fee = 1.8,
580
+ }: {
581
+ signer: OfflineSigner;
582
+ operator: string;
583
+ gasStation?: boolean;
584
+ fee?: StdFee | 'auto' | number;
585
+ }) {
586
+ const client = await createSaasClientBy({
587
+ rpcEndpoint: this.rpcEndpoint,
588
+ wallet: signer,
589
+ contractAddress: this.saasAddress,
590
+ });
591
+
592
+ if (gasStation && typeof fee !== 'object') {
593
+ // When gasStation is true and fee is not StdFee, we need to simulate first then add granter
594
+ const [{ address }] = await signer.getAccounts();
595
+ const contractClient = await this.contractClient({ signer });
596
+ const msg = {
597
+ remove_operator: {
598
+ operator,
599
+ },
600
+ };
601
+ const gasEstimation = await contractClient.simulate(
602
+ address,
603
+ [
604
+ {
605
+ typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
606
+ value: {
607
+ sender: address,
608
+ contract: this.saasAddress,
609
+ msg: new TextEncoder().encode(JSON.stringify(msg)),
610
+ },
611
+ },
612
+ ],
613
+ ''
614
+ );
615
+ const multiplier = typeof fee === 'number' ? fee : 1.8;
616
+ const gasPrice = GasPrice.fromString('10000000000peaka');
617
+ const calculatedFee = calculateFee(
618
+ Math.round(gasEstimation * multiplier),
619
+ gasPrice
620
+ );
621
+ const grantFee: StdFee = {
622
+ amount: calculatedFee.amount,
623
+ gas: calculatedFee.gas,
624
+ granter: this.saasAddress,
625
+ };
626
+ return client.removeOperator({ operator }, grantFee);
627
+ } else if (gasStation && typeof fee === 'object') {
628
+ // When gasStation is true and fee is StdFee, add granter
629
+ const grantFee: StdFee = {
630
+ ...fee,
631
+ granter: this.saasAddress,
632
+ };
633
+ return client.removeOperator({ operator }, grantFee);
634
+ }
635
+
636
+ return client.removeOperator({ operator }, fee);
637
+ }
638
+
639
+ async isSaasOperator({
640
+ signer,
641
+ operator,
642
+ }: {
643
+ signer: OfflineSigner;
644
+ operator: string;
645
+ }) {
646
+ const client = await createSaasClientBy({
647
+ rpcEndpoint: this.rpcEndpoint,
648
+ wallet: signer,
649
+ contractAddress: this.saasAddress,
650
+ });
651
+ return client.isOperator({ address: operator });
652
+ }
653
+
654
+ async depositSaas({
655
+ signer,
656
+ amount,
657
+ gasStation = false,
658
+ fee = 1.8,
659
+ }: {
660
+ signer: OfflineSigner;
661
+ amount: string;
662
+ gasStation?: boolean;
663
+ fee?: StdFee | 'auto' | number;
664
+ }) {
665
+ const client = await createSaasClientBy({
666
+ rpcEndpoint: this.rpcEndpoint,
667
+ wallet: signer,
668
+ contractAddress: this.saasAddress,
669
+ });
670
+
671
+ const funds = [
672
+ {
673
+ denom: 'peaka',
674
+ amount: amount,
675
+ },
676
+ ];
677
+
678
+ if (gasStation && typeof fee !== 'object') {
679
+ // When gasStation is true and fee is not StdFee, we need to simulate first then add granter
680
+ const [{ address }] = await signer.getAccounts();
681
+ const contractClient = await this.contractClient({ signer });
682
+ const msg = {
683
+ deposit: {},
684
+ };
685
+ const gasEstimation = await contractClient.simulate(
686
+ address,
687
+ [
688
+ {
689
+ typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
690
+ value: {
691
+ sender: address,
692
+ contract: this.saasAddress,
693
+ msg: new TextEncoder().encode(JSON.stringify(msg)),
694
+ funds,
695
+ },
696
+ },
697
+ ],
698
+ ''
699
+ );
700
+ const multiplier = typeof fee === 'number' ? fee : 1.8;
701
+ const gasPrice = GasPrice.fromString('10000000000peaka');
702
+ const calculatedFee = calculateFee(
703
+ Math.round(gasEstimation * multiplier),
704
+ gasPrice
705
+ );
706
+ const grantFee: StdFee = {
707
+ amount: calculatedFee.amount,
708
+ gas: calculatedFee.gas,
709
+ granter: this.saasAddress,
710
+ };
711
+ return client.deposit(grantFee, undefined, funds);
712
+ } else if (gasStation && typeof fee === 'object') {
713
+ // When gasStation is true and fee is StdFee, add granter
714
+ const grantFee: StdFee = {
715
+ ...fee,
716
+ granter: this.saasAddress,
717
+ };
718
+ return client.deposit(grantFee, undefined, funds);
719
+ }
720
+
721
+ return client.deposit(fee, undefined, funds);
722
+ }
723
+
724
+ async withdrawSaas({
725
+ signer,
726
+ amount,
727
+ gasStation = false,
728
+ fee = 1.8,
729
+ }: {
730
+ signer: OfflineSigner;
731
+ amount: string;
732
+ gasStation?: boolean;
733
+ fee?: StdFee | 'auto' | number;
734
+ }) {
735
+ const client = await createSaasClientBy({
736
+ rpcEndpoint: this.rpcEndpoint,
737
+ wallet: signer,
738
+ contractAddress: this.saasAddress,
739
+ });
740
+
741
+ if (gasStation && typeof fee !== 'object') {
742
+ // When gasStation is true and fee is not StdFee, we need to simulate first then add granter
743
+ const [{ address }] = await signer.getAccounts();
744
+ const contractClient = await this.contractClient({ signer });
745
+ const msg = {
746
+ withdraw: {
747
+ amount,
748
+ },
749
+ };
750
+ const gasEstimation = await contractClient.simulate(
751
+ address,
752
+ [
753
+ {
754
+ typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',
755
+ value: {
756
+ sender: address,
757
+ contract: this.saasAddress,
758
+ msg: new TextEncoder().encode(JSON.stringify(msg)),
759
+ },
760
+ },
761
+ ],
762
+ ''
763
+ );
764
+ const multiplier = typeof fee === 'number' ? fee : 1.8;
765
+ const gasPrice = GasPrice.fromString('10000000000peaka');
766
+ const calculatedFee = calculateFee(
767
+ Math.round(gasEstimation * multiplier),
768
+ gasPrice
769
+ );
770
+ const grantFee: StdFee = {
771
+ amount: calculatedFee.amount,
772
+ gas: calculatedFee.gas,
773
+ granter: this.saasAddress,
774
+ };
775
+ return client.withdraw({ amount }, grantFee);
776
+ } else if (gasStation && typeof fee === 'object') {
777
+ // When gasStation is true and fee is StdFee, add granter
778
+ const grantFee: StdFee = {
779
+ ...fee,
780
+ granter: this.saasAddress,
781
+ };
782
+ return client.withdraw({ amount }, grantFee);
783
+ }
784
+
785
+ return client.withdraw({ amount }, fee);
786
+ }
787
+
251
788
  async queryRoundInfo({
252
789
  signer,
253
790
  roundAddress,
@@ -321,6 +858,20 @@ export class Contract {
321
858
  });
322
859
  }
323
860
 
861
+ async saasClient({
862
+ signer,
863
+ contractAddress,
864
+ }: {
865
+ signer: OfflineSigner;
866
+ contractAddress: string;
867
+ }) {
868
+ return createSaasClientBy({
869
+ rpcEndpoint: this.rpcEndpoint,
870
+ wallet: signer,
871
+ contractAddress,
872
+ });
873
+ }
874
+
324
875
  async contractClient({ signer }: { signer: OfflineSigner }) {
325
876
  return createContractClientByWallet(this.rpcEndpoint, signer);
326
877
  }