@dorafactory/maci-sdk 0.1.2 → 0.1.3-pre.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.
Files changed (39) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +2371 -975
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +2369 -975
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/libs/const.d.ts +1 -2
  7. package/dist/libs/contract/config.d.ts +12 -0
  8. package/dist/libs/contract/contract.d.ts +66 -4
  9. package/dist/libs/contract/ts/AMaci.client.d.ts +25 -3
  10. package/dist/libs/contract/ts/AMaci.types.d.ts +26 -1
  11. package/dist/libs/contract/ts/ApiMaci.client.d.ts +170 -0
  12. package/dist/libs/contract/ts/ApiMaci.types.d.ts +187 -0
  13. package/dist/libs/contract/ts/ApiSaas.client.d.ts +148 -0
  14. package/dist/libs/contract/ts/ApiSaas.types.d.ts +126 -0
  15. package/dist/libs/contract/ts/Registry.client.d.ts +17 -7
  16. package/dist/libs/contract/ts/Registry.types.d.ts +16 -5
  17. package/dist/libs/contract/types.d.ts +15 -3
  18. package/dist/libs/crypto/bigintUtils.d.ts +2 -0
  19. package/dist/libs/maci/maci.d.ts +34 -4
  20. package/dist/maci.d.ts +47 -3
  21. package/dist/types/index.d.ts +2 -2
  22. package/package.json +1 -1
  23. package/src/index.ts +5 -1
  24. package/src/libs/const.ts +5 -6
  25. package/src/libs/contract/config.ts +36 -0
  26. package/src/libs/contract/contract.ts +611 -6
  27. package/src/libs/contract/ts/AMaci.client.ts +66 -0
  28. package/src/libs/contract/ts/AMaci.types.ts +30 -1
  29. package/src/libs/contract/ts/ApiMaci.client.ts +459 -0
  30. package/src/libs/contract/ts/ApiMaci.types.ts +188 -0
  31. package/src/libs/contract/ts/ApiSaas.client.ts +581 -0
  32. package/src/libs/contract/ts/ApiSaas.types.ts +144 -0
  33. package/src/libs/contract/ts/Registry.client.ts +57 -9
  34. package/src/libs/contract/ts/Registry.types.ts +18 -5
  35. package/src/libs/contract/types.ts +16 -3
  36. package/src/libs/crypto/bigintUtils.ts +28 -0
  37. package/src/libs/maci/maci.ts +190 -9
  38. package/src/maci.ts +86 -4
  39. package/src/types/index.ts +2 -2
@@ -17,12 +17,14 @@ import {
17
17
  Uint256,
18
18
  Timestamp,
19
19
  Uint64,
20
+ Decimal,
20
21
  PubKey,
21
22
  RoundInfo,
22
23
  VotingTime,
23
- Whitelist,
24
- WhitelistConfig,
24
+ WhitelistBase,
25
+ WhitelistBaseConfig,
25
26
  ValidatorSet,
27
+ CircuitChargeConfig,
26
28
  QueryMsg,
27
29
  AdminResponse,
28
30
  String,
@@ -38,6 +40,7 @@ export interface RegistryReadOnlyInterface {
38
40
  getValidatorOperator: ({ address }: { address: Addr }) => Promise<Addr>;
39
41
  getMaciOperatorPubkey: ({ address }: { address: Addr }) => Promise<PubKey>;
40
42
  getMaciOperatorIdentity: ({ address }: { address: Addr }) => Promise<String>;
43
+ getCircuitChargeConfig: () => Promise<CircuitChargeConfig>;
41
44
  }
42
45
  export class RegistryQueryClient implements RegistryReadOnlyInterface {
43
46
  client: CosmWasmClient;
@@ -53,6 +56,7 @@ export class RegistryQueryClient implements RegistryReadOnlyInterface {
53
56
  this.getValidatorOperator = this.getValidatorOperator.bind(this);
54
57
  this.getMaciOperatorPubkey = this.getMaciOperatorPubkey.bind(this);
55
58
  this.getMaciOperatorIdentity = this.getMaciOperatorIdentity.bind(this);
59
+ this.getCircuitChargeConfig = this.getCircuitChargeConfig.bind(this);
56
60
  }
57
61
  admin = async (): Promise<AdminResponse> => {
58
62
  return this.client.queryContractSmart(this.contractAddress, {
@@ -116,6 +120,11 @@ export class RegistryQueryClient implements RegistryReadOnlyInterface {
116
120
  },
117
121
  });
118
122
  };
123
+ getCircuitChargeConfig = async (): Promise<CircuitChargeConfig> => {
124
+ return this.client.queryContractSmart(this.contractAddress, {
125
+ get_circuit_charge_config: {},
126
+ });
127
+ };
119
128
  }
120
129
  export interface RegistryInterface extends RegistryReadOnlyInterface {
121
130
  contractAddress: string;
@@ -154,25 +163,27 @@ export interface RegistryInterface extends RegistryReadOnlyInterface {
154
163
  {
155
164
  certificationSystem,
156
165
  circuitType,
157
- maxOption,
158
166
  maxVoter,
159
167
  operator,
168
+ oracleWhitelistPubkey,
160
169
  preDeactivateRoot,
161
170
  roundInfo,
162
171
  voiceCreditAmount,
172
+ voteOptionMap,
163
173
  votingTime,
164
174
  whitelist,
165
175
  }: {
166
176
  certificationSystem: Uint256;
167
177
  circuitType: Uint256;
168
- maxOption: Uint256;
169
178
  maxVoter: Uint256;
170
179
  operator: Addr;
180
+ oracleWhitelistPubkey?: string;
171
181
  preDeactivateRoot: Uint256;
172
182
  roundInfo: RoundInfo;
173
183
  voiceCreditAmount: Uint256;
184
+ voteOptionMap: string[];
174
185
  votingTime: VotingTime;
175
- whitelist?: Whitelist;
186
+ whitelist?: WhitelistBase;
176
187
  },
177
188
  fee?: number | StdFee | 'auto',
178
189
  memo?: string,
@@ -218,6 +229,16 @@ export interface RegistryInterface extends RegistryReadOnlyInterface {
218
229
  memo?: string,
219
230
  _funds?: Coin[]
220
231
  ) => Promise<ExecuteResult>;
232
+ changeChargeConfig: (
233
+ {
234
+ config,
235
+ }: {
236
+ config: CircuitChargeConfig;
237
+ },
238
+ fee?: number | StdFee | 'auto',
239
+ memo?: string,
240
+ _funds?: Coin[]
241
+ ) => Promise<ExecuteResult>;
221
242
  }
222
243
  export class RegistryClient
223
244
  extends RegistryQueryClient
@@ -243,6 +264,7 @@ export class RegistryClient
243
264
  this.removeValidator = this.removeValidator.bind(this);
244
265
  this.updateAmaciCodeId = this.updateAmaciCodeId.bind(this);
245
266
  this.changeOperator = this.changeOperator.bind(this);
267
+ this.changeChargeConfig = this.changeChargeConfig.bind(this);
246
268
  }
247
269
  setMaciOperator = async (
248
270
  {
@@ -317,25 +339,27 @@ export class RegistryClient
317
339
  {
318
340
  certificationSystem,
319
341
  circuitType,
320
- maxOption,
321
342
  maxVoter,
322
343
  operator,
344
+ oracleWhitelistPubkey,
323
345
  preDeactivateRoot,
324
346
  roundInfo,
325
347
  voiceCreditAmount,
348
+ voteOptionMap,
326
349
  votingTime,
327
350
  whitelist,
328
351
  }: {
329
352
  certificationSystem: Uint256;
330
353
  circuitType: Uint256;
331
- maxOption: Uint256;
332
354
  maxVoter: Uint256;
333
355
  operator: Addr;
356
+ oracleWhitelistPubkey?: string;
334
357
  preDeactivateRoot: Uint256;
335
358
  roundInfo: RoundInfo;
336
359
  voiceCreditAmount: Uint256;
360
+ voteOptionMap: string[];
337
361
  votingTime: VotingTime;
338
- whitelist?: Whitelist;
362
+ whitelist?: WhitelistBase;
339
363
  },
340
364
  fee: number | StdFee | 'auto' = 'auto',
341
365
  memo?: string,
@@ -348,12 +372,13 @@ export class RegistryClient
348
372
  create_round: {
349
373
  certification_system: certificationSystem,
350
374
  circuit_type: circuitType,
351
- max_option: maxOption,
352
375
  max_voter: maxVoter,
353
376
  operator,
377
+ oracle_whitelist_pubkey: oracleWhitelistPubkey,
354
378
  pre_deactivate_root: preDeactivateRoot,
355
379
  round_info: roundInfo,
356
380
  voice_credit_amount: voiceCreditAmount,
381
+ vote_option_map: voteOptionMap,
357
382
  voting_time: votingTime,
358
383
  whitelist,
359
384
  },
@@ -455,4 +480,27 @@ export class RegistryClient
455
480
  _funds
456
481
  );
457
482
  };
483
+ changeChargeConfig = async (
484
+ {
485
+ config,
486
+ }: {
487
+ config: CircuitChargeConfig;
488
+ },
489
+ fee: number | StdFee | 'auto' = 'auto',
490
+ memo?: string,
491
+ _funds?: Coin[]
492
+ ): Promise<ExecuteResult> => {
493
+ return await this.client.execute(
494
+ this.sender,
495
+ this.contractAddress,
496
+ {
497
+ change_charge_config: {
498
+ config,
499
+ },
500
+ },
501
+ fee,
502
+ memo,
503
+ _funds
504
+ );
505
+ };
458
506
  }
@@ -30,14 +30,15 @@ export type ExecuteMsg =
30
30
  create_round: {
31
31
  certification_system: Uint256;
32
32
  circuit_type: Uint256;
33
- max_option: Uint256;
34
33
  max_voter: Uint256;
35
34
  operator: Addr;
35
+ oracle_whitelist_pubkey?: string | null;
36
36
  pre_deactivate_root: Uint256;
37
37
  round_info: RoundInfo;
38
38
  voice_credit_amount: Uint256;
39
+ vote_option_map: string[];
39
40
  voting_time: VotingTime;
40
- whitelist?: Whitelist | null;
41
+ whitelist?: WhitelistBase | null;
41
42
  };
42
43
  }
43
44
  | {
@@ -59,10 +60,16 @@ export type ExecuteMsg =
59
60
  change_operator: {
60
61
  address: Addr;
61
62
  };
63
+ }
64
+ | {
65
+ change_charge_config: {
66
+ config: CircuitChargeConfig;
67
+ };
62
68
  };
63
69
  export type Uint256 = string;
64
70
  export type Timestamp = Uint64;
65
71
  export type Uint64 = string;
72
+ export type Decimal = string;
66
73
  export interface PubKey {
67
74
  x: Uint256;
68
75
  y: Uint256;
@@ -76,15 +83,18 @@ export interface VotingTime {
76
83
  end_time: Timestamp;
77
84
  start_time: Timestamp;
78
85
  }
79
- export interface Whitelist {
80
- users: WhitelistConfig[];
86
+ export interface WhitelistBase {
87
+ users: WhitelistBaseConfig[];
81
88
  }
82
- export interface WhitelistConfig {
89
+ export interface WhitelistBaseConfig {
83
90
  addr: Addr;
84
91
  }
85
92
  export interface ValidatorSet {
86
93
  addresses: Addr[];
87
94
  }
95
+ export interface CircuitChargeConfig {
96
+ fee_rate: Decimal;
97
+ }
88
98
  export type QueryMsg =
89
99
  | {
90
100
  admin: {};
@@ -119,6 +129,9 @@ export type QueryMsg =
119
129
  get_maci_operator_identity: {
120
130
  address: Addr;
121
131
  };
132
+ }
133
+ | {
134
+ get_circuit_charge_config: {};
122
135
  };
123
136
  export interface AdminResponse {
124
137
  admin: Addr;
@@ -1,7 +1,7 @@
1
1
  import { OfflineSigner } from '@cosmjs/proto-signing';
2
2
  import { StdFee } from '@cosmjs/amino';
3
3
 
4
- import { Whitelist as RegistryWhitelist } from './ts/Registry.types';
4
+ import { WhitelistBase as RegistryWhitelist } from './ts/Registry.types';
5
5
  import { Whitelist as MaciWhitelist } from './ts/Maci.types';
6
6
  import {
7
7
  MaciCircuitType,
@@ -22,11 +22,12 @@ export type CreateRoundParams = {
22
22
 
23
23
  export type CreateAMaciRoundParams = {
24
24
  maxVoter: number;
25
- maxOption: number;
25
+ voteOptionMap: string[];
26
26
  operator: string;
27
- whitelist: RegistryWhitelist;
27
+ whitelist?: RegistryWhitelist;
28
28
  voiceCreditAmount: string;
29
29
  preDeactivateRoot?: string;
30
+ oracleWhitelistPubkey?: string;
30
31
  } & CreateRoundParams;
31
32
 
32
33
  export type CreateMaciRoundParams = {
@@ -58,3 +59,15 @@ export type CreateSaasOracleMaciRoundParams = {
58
59
  gasStation?: boolean;
59
60
  fee?: StdFee | 'auto' | number;
60
61
  } & CreateRoundParams;
62
+
63
+ export type CreateApiSaasAmaciRoundParams = {
64
+ maxVoter: number;
65
+ voteOptionMap: string[];
66
+ operator: string;
67
+ whitelist?: RegistryWhitelist;
68
+ voiceCreditAmount: string;
69
+ preDeactivateRoot?: string;
70
+ oracleWhitelistPubkey?: string;
71
+ gasStation?: boolean;
72
+ fee?: StdFee | 'auto' | number;
73
+ } & CreateRoundParams;
@@ -29,3 +29,31 @@ export const bigInt2Buffer = (i: bigint) => {
29
29
  }
30
30
  return Buffer.from(hex, 'hex');
31
31
  };
32
+
33
+ export const buffer2Bigint = (buffer: Buffer | Uint8Array): bigint => {
34
+ const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
35
+ const hex = buf.toString('hex');
36
+ return BigInt('0x' + hex);
37
+ };
38
+
39
+ export const destringizing = (
40
+ o: MixedData<string>,
41
+ path: MixedData<string>[] = []
42
+ ): MixedData<bigint> => {
43
+ if (path.includes(o)) {
44
+ throw new Error('loop nesting!');
45
+ }
46
+ const newPath = [...path, o];
47
+
48
+ if (Array.isArray(o)) {
49
+ return o.map((item) => destringizing(item, newPath));
50
+ } else if (typeof o === 'object' && o !== null) {
51
+ const output: { [key: string]: MixedData<bigint> } = {};
52
+ for (const key in o) {
53
+ output[key] = destringizing(o[key], newPath);
54
+ }
55
+ return output;
56
+ } else {
57
+ return BigInt(o);
58
+ }
59
+ };
@@ -469,7 +469,7 @@ export class MACI {
469
469
  contractAddress: string;
470
470
  maciKeypair?: Keypair;
471
471
  oracleCertificate?: {
472
- amount: string;
472
+ amount?: string;
473
473
  signature: string;
474
474
  };
475
475
  gasStation?: boolean;
@@ -489,23 +489,93 @@ export class MACI {
489
489
  signer,
490
490
  });
491
491
 
492
- if (oracleCertificate) {
492
+ // If oracleCertificate has data and amount has data, use signupOracle
493
+ if (oracleCertificate && oracleCertificate.amount) {
493
494
  return await this.signupOracle({
494
495
  client,
495
496
  address,
496
497
  pubKey: maciKeypair.pubKey,
497
498
  contractAddress,
498
- oracleCertificate,
499
+ oracleCertificate: {
500
+ amount: oracleCertificate.amount,
501
+ signature: oracleCertificate.signature,
502
+ },
499
503
  gasStation,
500
504
  fee,
501
505
  });
502
506
  } else {
507
+ // If oracleCertificate has data but amount is missing, or oracleCertificate is missing, use signupSimple
503
508
  return await this.signupSimple({
504
509
  client,
505
510
  address,
506
511
  pubKey: maciKeypair.pubKey,
507
512
  contractAddress,
513
+ certificate: oracleCertificate?.signature,
514
+ gasStation,
515
+ fee,
516
+ });
517
+ }
518
+ } catch (error) {
519
+ throw Error(`Signup failed! ${error}`);
520
+ }
521
+ }
522
+
523
+ async rawSignup({
524
+ signer,
525
+ address,
526
+ contractAddress,
527
+ pubKey,
528
+ oracleCertificate,
529
+ gasStation = false,
530
+ granter,
531
+ fee,
532
+ }: {
533
+ signer: OfflineSigner;
534
+ address?: string;
535
+ contractAddress: string;
536
+ pubKey: PubKey;
537
+ oracleCertificate?: {
538
+ amount?: string;
539
+ signature: string;
540
+ };
541
+ gasStation?: boolean;
542
+ granter?: string;
543
+ fee?: StdFee | 'auto' | number;
544
+ }) {
545
+ try {
546
+ if (!address) {
547
+ address = (await signer.getAccounts())[0].address;
548
+ }
549
+
550
+ const client = await this.contract.contractClient({
551
+ signer,
552
+ });
553
+
554
+ // If oracleCertificate has data and amount has data, use signupOracle
555
+ if (oracleCertificate && oracleCertificate.amount) {
556
+ return await this.signupOracle({
557
+ client,
558
+ address,
559
+ pubKey,
560
+ contractAddress,
561
+ oracleCertificate: {
562
+ amount: oracleCertificate.amount,
563
+ signature: oracleCertificate.signature,
564
+ },
565
+ gasStation,
566
+ granter,
567
+ fee,
568
+ });
569
+ } else {
570
+ // If oracleCertificate has data but amount is missing, or oracleCertificate is missing, use signupSimple
571
+ return await this.signupSimple({
572
+ client,
573
+ address,
574
+ pubKey,
575
+ contractAddress,
576
+ certificate: oracleCertificate?.signature,
508
577
  gasStation,
578
+ granter,
509
579
  fee,
510
580
  });
511
581
  }
@@ -673,12 +743,115 @@ export class MACI {
673
743
  }
674
744
  }
675
745
 
746
+ async rawVote({
747
+ signer,
748
+ address,
749
+ contractAddress,
750
+ pubKey,
751
+ payload,
752
+ gasStation = false,
753
+ granter,
754
+ fee = 1.8,
755
+ }: {
756
+ signer: OfflineSigner;
757
+ address?: string;
758
+ contractAddress: string;
759
+ pubKey: PubKey;
760
+ payload: {
761
+ msg: bigint[];
762
+ encPubkeys: PubKey;
763
+ }[];
764
+ gasStation?: boolean;
765
+ granter?: string;
766
+ fee?: StdFee | 'auto' | number;
767
+ }) {
768
+ const stateIdx = await this.getStateIdxByPubKey({
769
+ contractAddress,
770
+ pubKey,
771
+ });
772
+
773
+ if (stateIdx === -1) {
774
+ throw new Error(
775
+ 'State index is not set, Please signup or addNewKey first'
776
+ );
777
+ }
778
+
779
+ try {
780
+ const round = await this.indexer.getRoundWithFields(contractAddress, [
781
+ 'maciType',
782
+ 'voiceCreditAmount',
783
+ ]);
784
+
785
+ if (isErrorResponse(round)) {
786
+ throw new Error(
787
+ `Failed to get round info: ${round.error.type} ${round.error.message}`
788
+ );
789
+ }
790
+
791
+ let voiceCreditBalance;
792
+ if (round.data.round.maciType === 'aMACI') {
793
+ const isWhiteListed = await this.isWhitelisted({
794
+ signer,
795
+ address,
796
+ contractAddress,
797
+ });
798
+
799
+ if (isWhiteListed) {
800
+ const round = await this.indexer.getRoundWithFields(contractAddress, [
801
+ 'voiceCreditAmount',
802
+ ]);
803
+
804
+ if (!isErrorResponse(round)) {
805
+ if (round.data.round.voiceCreditAmount) {
806
+ voiceCreditBalance = round.data.round.voiceCreditAmount;
807
+ } else {
808
+ voiceCreditBalance = '0';
809
+ }
810
+ } else {
811
+ throw new Error(
812
+ `Failed to query amaci voice credit: ${round.error.type} ${round.error.message}`
813
+ );
814
+ }
815
+ } else {
816
+ voiceCreditBalance = '0';
817
+ }
818
+ } else {
819
+ voiceCreditBalance = await this.getVoiceCreditBalance({
820
+ signer,
821
+ stateIdx,
822
+ contractAddress,
823
+ });
824
+ }
825
+
826
+ if (!address) {
827
+ address = (await signer.getAccounts())[0].address;
828
+ }
829
+
830
+ const client = await this.contract.contractClient({
831
+ signer,
832
+ });
833
+
834
+ return await this.publishMessage({
835
+ client,
836
+ address,
837
+ payload,
838
+ contractAddress,
839
+ gasStation,
840
+ granter,
841
+ fee,
842
+ });
843
+ } catch (error) {
844
+ throw Error(`Vote failed! ${error}`);
845
+ }
846
+ }
847
+
676
848
  async publishMessage({
677
849
  client,
678
850
  address,
679
851
  payload,
680
852
  contractAddress,
681
853
  gasStation,
854
+ granter,
682
855
  fee = 1.8,
683
856
  }: {
684
857
  client: SigningCosmWasmClient;
@@ -689,6 +862,7 @@ export class MACI {
689
862
  }[];
690
863
  contractAddress: string;
691
864
  gasStation: boolean;
865
+ granter?: string;
692
866
  fee?: StdFee | 'auto' | number;
693
867
  }) {
694
868
  const msgs: MsgExecuteContractEncodeObject[] = payload.map(
@@ -728,14 +902,14 @@ export class MACI {
728
902
  const grantFee: StdFee = {
729
903
  amount: calculatedFee.amount,
730
904
  gas: calculatedFee.gas,
731
- granter: contractAddress,
905
+ granter: granter || contractAddress,
732
906
  };
733
907
  return client.signAndBroadcast(address, msgs, grantFee);
734
908
  } else if (gasStation && typeof fee === 'object') {
735
909
  // When gasStation is true and fee is StdFee, add granter
736
910
  const grantFee: StdFee = {
737
911
  ...fee,
738
- granter: contractAddress,
912
+ granter: granter || contractAddress,
739
913
  };
740
914
  return client.signAndBroadcast(address, msgs, grantFee);
741
915
  }
@@ -748,18 +922,23 @@ export class MACI {
748
922
  address,
749
923
  pubKey,
750
924
  contractAddress,
925
+ certificate,
751
926
  gasStation,
927
+ granter,
752
928
  fee = 1.8,
753
929
  }: {
754
930
  client: SigningCosmWasmClient;
755
931
  address: string;
756
932
  pubKey: PubKey;
757
933
  contractAddress: string;
934
+ certificate?: string;
758
935
  gasStation?: boolean;
936
+ granter?: string;
759
937
  fee?: StdFee | 'auto' | number;
760
938
  }) {
761
939
  const msg = {
762
940
  sign_up: {
941
+ certificate,
763
942
  pubkey: {
764
943
  x: pubKey[0].toString(),
765
944
  y: pubKey[1].toString(),
@@ -792,14 +971,14 @@ export class MACI {
792
971
  const grantFee: StdFee = {
793
972
  amount: calculatedFee.amount,
794
973
  gas: calculatedFee.gas,
795
- granter: contractAddress,
974
+ granter: granter || contractAddress,
796
975
  };
797
976
  return client.execute(address, contractAddress, msg, grantFee);
798
977
  } else if (gasStation === true && typeof fee === 'object') {
799
978
  // When gasStation is true and fee is StdFee, add granter
800
979
  const grantFee: StdFee = {
801
980
  ...fee,
802
- granter: contractAddress,
981
+ granter: granter || contractAddress,
803
982
  };
804
983
  return client.execute(address, contractAddress, msg, grantFee);
805
984
  }
@@ -814,6 +993,7 @@ export class MACI {
814
993
  contractAddress,
815
994
  oracleCertificate,
816
995
  gasStation,
996
+ granter,
817
997
  fee = 1.8,
818
998
  }: {
819
999
  client: SigningCosmWasmClient;
@@ -825,6 +1005,7 @@ export class MACI {
825
1005
  signature: string;
826
1006
  };
827
1007
  gasStation?: boolean;
1008
+ granter?: string;
828
1009
  fee?: StdFee | 'auto' | number;
829
1010
  }) {
830
1011
  const msg = {
@@ -863,14 +1044,14 @@ export class MACI {
863
1044
  const grantFee: StdFee = {
864
1045
  amount: calculatedFee.amount,
865
1046
  gas: calculatedFee.gas,
866
- granter: contractAddress,
1047
+ granter: granter || contractAddress,
867
1048
  };
868
1049
  return client.execute(address, contractAddress, msg, grantFee);
869
1050
  } else if (gasStation === true && typeof fee === 'object') {
870
1051
  // When gasStation is true and fee is StdFee, add granter
871
1052
  const grantFee: StdFee = {
872
1053
  ...fee,
873
- granter: contractAddress,
1054
+ granter: granter || contractAddress,
874
1055
  };
875
1056
  return client.execute(address, contractAddress, msg, grantFee);
876
1057
  }