@0xpolygonid/js-sdk 1.33.1 → 1.34.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.
Files changed (71) hide show
  1. package/dist/browser/esm/index.js +1322 -781
  2. package/dist/browser/esm/index.js.map +1 -1
  3. package/dist/browser/umd/index.global.js +182 -59
  4. package/dist/browser/umd/index.global.js.map +1 -1
  5. package/dist/node/cjs/index.cjs +2059 -1495
  6. package/dist/node/cjs/index.cjs.map +1 -1
  7. package/dist/node/esm/index.js +1322 -781
  8. package/dist/node/esm/index.js.map +1 -1
  9. package/dist/types/circuits/auth-v3.d.ts +20 -0
  10. package/dist/types/circuits/auth-v3.d.ts.map +1 -0
  11. package/dist/types/circuits/index.d.ts +1 -0
  12. package/dist/types/circuits/index.d.ts.map +1 -1
  13. package/dist/types/circuits/models.d.ts +2 -0
  14. package/dist/types/circuits/models.d.ts.map +1 -1
  15. package/dist/types/iden3comm/constants.d.ts +2 -1
  16. package/dist/types/iden3comm/constants.d.ts.map +1 -1
  17. package/dist/types/iden3comm/handlers/auth.d.ts +4 -1
  18. package/dist/types/iden3comm/handlers/auth.d.ts.map +1 -1
  19. package/dist/types/iden3comm/handlers/contract-request.d.ts +1 -1
  20. package/dist/types/iden3comm/handlers/contract-request.d.ts.map +1 -1
  21. package/dist/types/iden3comm/handlers/credential-proposal.d.ts +2 -2
  22. package/dist/types/iden3comm/handlers/credential-proposal.d.ts.map +1 -1
  23. package/dist/types/iden3comm/handlers/fetch.d.ts +2 -2
  24. package/dist/types/iden3comm/handlers/fetch.d.ts.map +1 -1
  25. package/dist/types/iden3comm/handlers/message-handler.d.ts +12 -0
  26. package/dist/types/iden3comm/handlers/message-handler.d.ts.map +1 -1
  27. package/dist/types/iden3comm/handlers/payment.d.ts +18 -6
  28. package/dist/types/iden3comm/handlers/payment.d.ts.map +1 -1
  29. package/dist/types/iden3comm/handlers/refresh.d.ts +4 -1
  30. package/dist/types/iden3comm/handlers/refresh.d.ts.map +1 -1
  31. package/dist/types/iden3comm/handlers/revocation-status.d.ts +4 -4
  32. package/dist/types/iden3comm/handlers/revocation-status.d.ts.map +1 -1
  33. package/dist/types/iden3comm/packers/zkp.d.ts.map +1 -1
  34. package/dist/types/iden3comm/types/protocol/payment.d.ts +58 -9
  35. package/dist/types/iden3comm/types/protocol/payment.d.ts.map +1 -1
  36. package/dist/types/iden3comm/utils/accept-profile.d.ts +3 -0
  37. package/dist/types/iden3comm/utils/accept-profile.d.ts.map +1 -1
  38. package/dist/types/proof/proof-service.d.ts +13 -0
  39. package/dist/types/proof/proof-service.d.ts.map +1 -1
  40. package/dist/types/proof/provers/inputs-generator.d.ts.map +1 -1
  41. package/dist/types/utils/index.d.ts +2 -0
  42. package/dist/types/utils/index.d.ts.map +1 -1
  43. package/dist/types/utils/payments/evm.d.ts +19 -0
  44. package/dist/types/utils/payments/evm.d.ts.map +1 -0
  45. package/dist/types/utils/payments/solana.d.ts +88 -0
  46. package/dist/types/utils/payments/solana.d.ts.map +1 -0
  47. package/dist/types/verifiable/constants.d.ts +16 -3
  48. package/dist/types/verifiable/constants.d.ts.map +1 -1
  49. package/package.json +7 -3
  50. package/src/circuits/auth-v3.ts +19 -0
  51. package/src/circuits/index.ts +1 -0
  52. package/src/circuits/models.ts +5 -1
  53. package/src/iden3comm/constants.ts +2 -1
  54. package/src/iden3comm/handlers/auth.ts +54 -11
  55. package/src/iden3comm/handlers/contract-request.ts +1 -1
  56. package/src/iden3comm/handlers/credential-proposal.ts +12 -6
  57. package/src/iden3comm/handlers/fetch.ts +29 -6
  58. package/src/iden3comm/handlers/message-handler.ts +28 -2
  59. package/src/iden3comm/handlers/payment.ts +190 -144
  60. package/src/iden3comm/handlers/refresh.ts +9 -13
  61. package/src/iden3comm/handlers/revocation-status.ts +9 -7
  62. package/src/iden3comm/packers/zkp.ts +18 -8
  63. package/src/iden3comm/types/protocol/payment.ts +79 -10
  64. package/src/iden3comm/utils/accept-profile.ts +24 -0
  65. package/src/proof/proof-service.ts +93 -25
  66. package/src/proof/provers/inputs-generator.ts +2 -0
  67. package/src/proof/provers/prover.ts +1 -1
  68. package/src/utils/index.ts +2 -0
  69. package/src/utils/payments/evm.ts +152 -0
  70. package/src/utils/payments/solana.ts +360 -0
  71. package/src/verifiable/constants.ts +17 -3
@@ -31,6 +31,8 @@ export type PaymentRequestInfo = {
31
31
  | Iden3PaymentRequestCryptoV1
32
32
  | Iden3PaymentRailsRequestV1
33
33
  | Iden3PaymentRailsERC20RequestV1
34
+ | Iden3PaymentRailsSolanaRequestV1
35
+ | Iden3PaymentRailsSolanaSPLRequestV1
34
36
  )[];
35
37
  description?: string;
36
38
  };
@@ -47,6 +49,7 @@ export type Iden3PaymentRequestCryptoV1 = {
47
49
  expiration?: string;
48
50
  };
49
51
 
52
+ /** @beta Iden3PaymentRailsRequestV1 is struct the represents EVM native payment rails request */
50
53
  export type Iden3PaymentRailsRequestV1 = {
51
54
  type: PaymentRequestDataType.Iden3PaymentRailsRequestV1;
52
55
  '@context': string | (string | object)[];
@@ -58,12 +61,32 @@ export type Iden3PaymentRailsRequestV1 = {
58
61
  proof: EthereumEip712Signature2021 | EthereumEip712Signature2021[];
59
62
  };
60
63
 
64
+ /** @beta Iden3PaymentRailsERC20RequestV1 is struct the represents EVM ERC 20 payment rails request */
61
65
  export type Iden3PaymentRailsERC20RequestV1 = Omit<Required<Iden3PaymentRailsRequestV1>, 'type'> & {
62
66
  tokenAddress: string;
63
67
  features?: PaymentFeatures[];
64
68
  type: PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1;
65
69
  };
66
70
 
71
+ /** @beta Iden3PaymentRailsSolanaRequestV1 is struct the represents Solana native payment rails request */
72
+ export type Iden3PaymentRailsSolanaRequestV1 = Omit<
73
+ Required<Iden3PaymentRailsRequestV1>,
74
+ 'type' | 'proof'
75
+ > & {
76
+ type: PaymentRequestDataType.Iden3PaymentRailsSolanaRequestV1;
77
+ proof: Iden3SolanaEd25519SignatureV1 | Iden3SolanaEd25519SignatureV1[];
78
+ };
79
+
80
+ /** @beta Iden3PaymentRailsSolanaSPLRequestV1 is struct the represents Solana SPL payment rails request */
81
+ export type Iden3PaymentRailsSolanaSPLRequestV1 = Omit<
82
+ Required<Iden3PaymentRailsERC20RequestV1>,
83
+ 'type' | 'proof'
84
+ > & {
85
+ type: PaymentRequestDataType.Iden3PaymentRailsSolanaSPLRequestV1;
86
+ proof: Iden3SolanaEd25519SignatureV1 | Iden3SolanaEd25519SignatureV1[];
87
+ };
88
+
89
+ /** @beta EthereumEip712Signature2021 is struct the represents EIP-712 signature for Ethereum */
67
90
  export type EthereumEip712Signature2021 = {
68
91
  type: SupportedPaymentProofType.EthereumEip712Signature2021;
69
92
  proofPurpose: string;
@@ -82,6 +105,20 @@ export type EthereumEip712Signature2021 = {
82
105
  };
83
106
  };
84
107
 
108
+ /** @beta Iden3SolanaEd25519SignatureV1 is struct the represents Ed25519 signature for Solana Payment Instruction */
109
+ export type Iden3SolanaEd25519SignatureV1 = {
110
+ type: SupportedPaymentProofType.SolanaEd25519Signature2025;
111
+ proofPurpose: string;
112
+ proofValue: string;
113
+ created: string;
114
+ verificationMethod: string;
115
+ domain: {
116
+ version: 'SolanaEd25519NativeV1' | 'SolanaEd25519SPLV1';
117
+ chainId: string;
118
+ verifyingContract: string;
119
+ };
120
+ };
121
+
85
122
  /** @beta PaymentMessage is struct the represents payment message */
86
123
  export type PaymentMessage = BasicMessage & {
87
124
  body: PaymentMessageBody;
@@ -128,19 +165,47 @@ export type Iden3PaymentRailsERC20V1 = {
128
165
  };
129
166
  };
130
167
 
168
+ /** @beta Iden3PaymentRailsSolanaV1 is struct the represents payment info for Iden3PaymentRailsSolanaV1 */
169
+ export type Iden3PaymentRailsSolanaV1 = {
170
+ nonce: string;
171
+ type: 'Iden3PaymentRailsSolanaV1';
172
+ '@context': string | (string | object)[];
173
+ paymentData: {
174
+ txId: string;
175
+ chainId: string;
176
+ };
177
+ };
178
+
179
+ /** @beta Iden3PaymentRailsSolanaSPLV1 is struct the represents payment info for Iden3PaymentRailsSolanaSPLV1 */
180
+ export type Iden3PaymentRailsSolanaSPLV1 = {
181
+ nonce: string;
182
+ type: 'Iden3PaymentRailsSolanaSPLV1';
183
+ '@context': string | (string | object)[];
184
+ paymentData: {
185
+ txId: string;
186
+ chainId: string;
187
+ tokenAddress: string;
188
+ };
189
+ };
190
+
131
191
  /** @beta MultiChainPaymentConfig is struct that represents payments contracts information for different chains */
132
192
  export type MultiChainPaymentConfig = {
133
193
  chainId: string;
134
194
  paymentRails: string;
135
195
  recipient: string;
136
- options: {
137
- id: string;
138
- type:
139
- | PaymentRequestDataType.Iden3PaymentRailsRequestV1
140
- | PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1;
141
- contractAddress?: string;
142
- features?: PaymentFeatures[];
143
- }[];
196
+ options: MultiChainPaymentConfigOption[];
197
+ };
198
+
199
+ /** @beta MultiChainPaymentConfigOption is struct that represents payment options for different chains */
200
+ export type MultiChainPaymentConfigOption = {
201
+ id: string;
202
+ type:
203
+ | PaymentRequestDataType.Iden3PaymentRailsRequestV1
204
+ | PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1
205
+ | PaymentRequestDataType.Iden3PaymentRailsSolanaRequestV1
206
+ | PaymentRequestDataType.Iden3PaymentRailsSolanaSPLRequestV1;
207
+ contractAddress?: string;
208
+ features?: PaymentFeatures[];
144
209
  };
145
210
 
146
211
  /**
@@ -150,7 +215,9 @@ export type MultiChainPaymentConfig = {
150
215
  export type PaymentRequestTypeUnion =
151
216
  | Iden3PaymentRequestCryptoV1
152
217
  | Iden3PaymentRailsRequestV1
153
- | Iden3PaymentRailsERC20RequestV1;
218
+ | Iden3PaymentRailsERC20RequestV1
219
+ | Iden3PaymentRailsSolanaRequestV1
220
+ | Iden3PaymentRailsSolanaSPLRequestV1;
154
221
 
155
222
  /**
156
223
  * @beta
@@ -159,4 +226,6 @@ export type PaymentRequestTypeUnion =
159
226
  export type PaymentTypeUnion =
160
227
  | Iden3PaymentCryptoV1
161
228
  | Iden3PaymentRailsV1
162
- | Iden3PaymentRailsERC20V1;
229
+ | Iden3PaymentRailsERC20V1
230
+ | Iden3PaymentRailsSolanaV1
231
+ | Iden3PaymentRailsSolanaSPLV1;
@@ -1,3 +1,4 @@
1
+ import { ProvingMethodAlg } from '@iden3/js-jwz';
1
2
  import {
2
3
  MediaType,
3
4
  ProtocolVersion,
@@ -27,6 +28,29 @@ function isAcceptJwzAlgorithms(value: string): boolean {
27
28
  return Object.values(AcceptJwzAlgorithms).includes(value as AcceptJwzAlgorithms);
28
29
  }
29
30
 
31
+ export const buildAcceptFromProvingMethodAlg = (provingMethodAlg: ProvingMethodAlg): string => {
32
+ const [alg, circuitId] = provingMethodAlg.toString().split(':');
33
+ return `${ProtocolVersion.V1};env=${MediaType.ZKPMessage};circuitId=${circuitId};alg=${alg}`;
34
+ };
35
+
36
+ export const acceptHasProvingMethodAlg = (
37
+ accept: string[],
38
+ provingMethodAlg: ProvingMethodAlg
39
+ ): boolean => {
40
+ const [provingAlg, provingCircuitId] = provingMethodAlg.toString().split(':');
41
+ for (const profile of accept) {
42
+ const { env, circuits, alg } = parseAcceptProfile(profile);
43
+ if (
44
+ env === MediaType.ZKPMessage &&
45
+ circuits?.includes(provingCircuitId as AcceptAuthCircuits) &&
46
+ (!alg || (alg as unknown as AcceptJwzAlgorithms)?.includes(provingAlg as AcceptJwzAlgorithms))
47
+ ) {
48
+ return true;
49
+ }
50
+ }
51
+ return false;
52
+ };
53
+
30
54
  export const buildAccept = (profiles: AcceptProfile[]): string[] => {
31
55
  const result = [];
32
56
  for (const profile of profiles) {
@@ -7,6 +7,8 @@ import {
7
7
  import {
8
8
  AuthV2Inputs,
9
9
  AuthV2PubSignals,
10
+ AuthV3Inputs,
11
+ AuthV3PubSignals,
10
12
  CircuitId,
11
13
  Operators,
12
14
  Query,
@@ -125,6 +127,7 @@ export interface IProofService {
125
127
  ): Promise<ZeroKnowledgeProofResponse>;
126
128
 
127
129
  /**
130
+ * @deprecated, use generateAuthInputs with CircuitId.AuthV2 instead
128
131
  * generates auth inputs
129
132
  *
130
133
  * @param {Uint8Array} hash - challenge that will be signed
@@ -135,6 +138,17 @@ export interface IProofService {
135
138
  generateAuthV2Inputs(hash: Uint8Array, did: DID, circuitId: CircuitId): Promise<Uint8Array>;
136
139
 
137
140
  /**
141
+ * generates Auth inputs
142
+ *
143
+ * @param {Uint8Array} hash - challenge that will be signed
144
+ * @param {DID} did - identity that will generate a proof
145
+ * @param {CircuitId} circuitId - circuit id for authentication
146
+ * @returns `Promise<Uint8Array>`
147
+ */
148
+ generateAuthInputs(hash: Uint8Array, did: DID, circuitId: CircuitId): Promise<Uint8Array>;
149
+
150
+ /**
151
+ * @deprecated, use generateAuthProof with CircuitId.AuthV2 instead
138
152
  * generates auth v2 proof from given identity
139
153
  *
140
154
  * @param {Uint8Array} hash - challenge that will be signed
@@ -397,30 +411,30 @@ export class ProofService implements IProofService {
397
411
  identifier: DID,
398
412
  opts?: AuthProofGenerationOptions
399
413
  ): Promise<ZeroKnowledgeProofAuthResponse> {
414
+ if (
415
+ circuitId !== CircuitId.AuthV2 &&
416
+ circuitId !== CircuitId.AuthV3 &&
417
+ circuitId !== CircuitId.AuthV3_8_32
418
+ ) {
419
+ throw new Error('CircuitId is not supported');
420
+ }
400
421
  if (!opts) {
401
422
  opts = {
402
423
  challenge: 0n
403
424
  };
404
425
  }
405
426
 
406
- let zkProof;
407
-
408
- switch (circuitId) {
409
- case CircuitId.AuthV2:
410
- {
411
- const challenge = opts.challenge
412
- ? BytesHelper.intToBytes(opts.challenge).reverse()
413
- : new Uint8Array(32);
414
- zkProof = await this.generateAuthV2Proof(challenge, identifier);
415
- }
416
- return {
417
- circuitId: circuitId,
418
- proof: zkProof.proof,
419
- pub_signals: zkProof.pub_signals
420
- };
421
- default:
422
- throw new Error(`CircuitId ${circuitId} is not supported`);
423
- }
427
+ const challenge = opts.challenge
428
+ ? BytesHelper.intToBytes(opts.challenge).reverse()
429
+ : new Uint8Array(32);
430
+ const authInputs = await this.generateAuthInputs(challenge, identifier, circuitId);
431
+
432
+ const zkProof = await this._prover.generate(authInputs, circuitId);
433
+ return {
434
+ circuitId: circuitId,
435
+ proof: zkProof.proof,
436
+ pub_signals: zkProof.pub_signals
437
+ };
424
438
  }
425
439
 
426
440
  /** {@inheritdoc IProofService.transitState} */
@@ -550,9 +564,50 @@ export class ProofService implements IProofService {
550
564
  return authInputs.inputsMarshal();
551
565
  }
552
566
 
567
+ /** {@inheritdoc IProofService.generateAuthInputs} */
568
+ async generateAuthInputs(hash: Uint8Array, did: DID, circuitId: CircuitId): Promise<Uint8Array> {
569
+ if (
570
+ circuitId !== CircuitId.AuthV2 &&
571
+ circuitId !== CircuitId.AuthV3 &&
572
+ circuitId !== CircuitId.AuthV3_8_32
573
+ ) {
574
+ throw new Error('CircuitId is not supported');
575
+ }
576
+
577
+ const { nonce: authProfileNonce, genesisDID } =
578
+ await this._identityWallet.getGenesisDIDMetadata(did);
579
+
580
+ const challenge = BytesHelper.bytesToInt(hash.reverse());
581
+
582
+ const authPrepared = await this._inputsGenerator.prepareAuthBJJCredential(genesisDID);
583
+
584
+ const signature = await this._identityWallet.signChallenge(challenge, authPrepared.credential);
585
+ const id = DID.idFromDID(genesisDID);
586
+ const stateProof = await this._stateStorage.getGISTProof(id.bigInt());
587
+
588
+ const gistProof = toGISTProof(stateProof);
589
+
590
+ const authInputs = new AuthV3Inputs(); // works for both v3 and v2
591
+ if (circuitId === CircuitId.AuthV3_8_32) {
592
+ authInputs.mtLevel = 8;
593
+ authInputs.mtLevelOnChain = 32;
594
+ }
595
+
596
+ authInputs.genesisID = id;
597
+ authInputs.profileNonce = BigInt(authProfileNonce);
598
+ authInputs.authClaim = authPrepared.coreClaim;
599
+ authInputs.authClaimIncMtp = authPrepared.incProof.proof;
600
+ authInputs.authClaimNonRevMtp = authPrepared.nonRevProof.proof;
601
+ authInputs.treeState = authPrepared.incProof.treeState;
602
+ authInputs.signature = signature;
603
+ authInputs.challenge = challenge;
604
+ authInputs.gistProof = gistProof;
605
+ return authInputs.inputsMarshal();
606
+ }
607
+
553
608
  /** {@inheritdoc IProofService.generateAuthV2Proof} */
554
609
  async generateAuthV2Proof(challenge: Uint8Array, did: DID): Promise<ZKProof> {
555
- const authInputs = await this.generateAuthV2Inputs(challenge, did, CircuitId.AuthV2);
610
+ const authInputs = await this.generateAuthInputs(challenge, did, CircuitId.AuthV2);
556
611
 
557
612
  const zkProof = await this._prover.generate(authInputs, CircuitId.AuthV2);
558
613
  return zkProof;
@@ -565,15 +620,28 @@ export class ProofService implements IProofService {
565
620
  acceptedStateTransitionDelay: PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY
566
621
  }
567
622
  ): Promise<boolean> {
568
- if (circuitId !== CircuitId.AuthV2) {
623
+ if (
624
+ circuitId !== CircuitId.AuthV2 &&
625
+ circuitId !== CircuitId.AuthV3 &&
626
+ circuitId !== CircuitId.AuthV3_8_32
627
+ ) {
569
628
  throw new Error(`CircuitId is not supported ${circuitId}`);
570
629
  }
571
630
 
572
- const authV2PubSignals = new AuthV2PubSignals().pubSignalsUnmarshal(
573
- byteEncoder.encode(JSON.stringify(pubSignals))
574
- );
575
- const gistRoot = authV2PubSignals.GISTRoot.bigInt();
576
- const userId = authV2PubSignals.userID.bigInt();
631
+ let gistRoot, userId;
632
+ if (circuitId === CircuitId.AuthV2) {
633
+ const authV2PubSignals = new AuthV2PubSignals().pubSignalsUnmarshal(
634
+ byteEncoder.encode(JSON.stringify(pubSignals))
635
+ );
636
+ gistRoot = authV2PubSignals.GISTRoot.bigInt();
637
+ userId = authV2PubSignals.userID.bigInt();
638
+ } else {
639
+ const authV3PubSignals = new AuthV3PubSignals().pubSignalsUnmarshal(
640
+ byteEncoder.encode(JSON.stringify(pubSignals))
641
+ );
642
+ gistRoot = authV3PubSignals.GISTRoot.bigInt();
643
+ userId = authV3PubSignals.userID.bigInt();
644
+ }
577
645
  const globalStateInfo = await this._stateStorage.getGISTRootInfo(gistRoot, userId);
578
646
 
579
647
  if (globalStateInfo.root !== gistRoot) {
@@ -102,6 +102,8 @@ export const circuitValidator: {
102
102
  [CircuitId.AtomicQueryV3]: { maxQueriesCount: 1, supportedOperations: allOperations },
103
103
  [CircuitId.AtomicQueryV3OnChain]: { maxQueriesCount: 1, supportedOperations: allOperations },
104
104
  [CircuitId.AuthV2]: { maxQueriesCount: 0, supportedOperations: [] },
105
+ [CircuitId.AuthV3]: { maxQueriesCount: 0, supportedOperations: [] },
106
+ [CircuitId.AuthV3_8_32]: { maxQueriesCount: 0, supportedOperations: [] },
105
107
  [CircuitId.StateTransition]: { maxQueriesCount: 0, supportedOperations: [] },
106
108
  [CircuitId.LinkedMultiQuery10]: { maxQueriesCount: 10, supportedOperations: allOperations }
107
109
  };
@@ -77,7 +77,7 @@ export class NativeProver implements IZKProver {
77
77
  throw new Error(`wasm file doesn't exist for circuit ${circuitId}`);
78
78
  }
79
79
 
80
- const witnessCalculator = await witnessBuilder(circuitData.wasm);
80
+ const witnessCalculator = await witnessBuilder(circuitData.wasm.buffer as ArrayBuffer);
81
81
 
82
82
  const parsedData = JSON.parse(byteDecoder.decode(inputs));
83
83
 
@@ -3,3 +3,5 @@ export * from './object';
3
3
  export * from './did-helper';
4
4
  export * from './message-bus';
5
5
  export * from './compare-func';
6
+ export * from './payments/solana';
7
+ export * from './payments/evm';
@@ -0,0 +1,152 @@
1
+ import { Signer, ethers } from 'ethers';
2
+ import {
3
+ EthereumEip712Signature2021,
4
+ Iden3PaymentRailsERC20RequestV1,
5
+ Iden3PaymentRailsRequestV1,
6
+ MultiChainPaymentConfigOption
7
+ } from '../../iden3comm';
8
+ import { PaymentRequestDataType, SupportedPaymentProofType } from '../../verifiable';
9
+ import { getUnixTimestamp } from '@iden3/js-iden3-core';
10
+ import { Resolvable } from 'did-resolver';
11
+
12
+ /**
13
+ * @beta
14
+ * buildEvmPayment creates an EVM-based payment request and signs it using EIP-712.
15
+ * @param {Signer} signer - EIP-712 compatible signer
16
+ * @param {MultiChainPaymentConfigOption} option - payment option configuration
17
+ * @param {string} chainId - EVM chain ID
18
+ * @param {string} paymentRails - payment rails contract address
19
+ * @param {string} recipient - recipient address
20
+ * @param {bigint} amount - payment amount in smallest units
21
+ * @param {Date} expirationDateRequired - expiration date
22
+ * @param {bigint} nonce - unique nonce for the payment
23
+ * @returns {Promise<Iden3PaymentRailsRequestV1 | Iden3PaymentRailsERC20RequestV1>} payment request object
24
+ */
25
+ export const buildEvmPayment = async (
26
+ signer: Signer,
27
+ option: MultiChainPaymentConfigOption,
28
+ chainId: string,
29
+ paymentRails: string,
30
+ recipient: string,
31
+ amount: bigint,
32
+ expirationDateRequired: Date,
33
+ nonce: bigint
34
+ ): Promise<Iden3PaymentRailsRequestV1 | Iden3PaymentRailsERC20RequestV1> => {
35
+ const typeUrl = `https://schema.iden3.io/core/json/${option.type}.json`;
36
+ const typesFetchResult = await fetch(typeUrl);
37
+ const types = await typesFetchResult.json();
38
+ delete types.EIP712Domain;
39
+ const paymentData =
40
+ option.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
41
+ ? {
42
+ recipient,
43
+ amount: amount,
44
+ expirationDate: getUnixTimestamp(expirationDateRequired),
45
+ nonce,
46
+ metadata: '0x'
47
+ }
48
+ : {
49
+ tokenAddress: option.contractAddress,
50
+ recipient,
51
+ amount: amount,
52
+ expirationDate: getUnixTimestamp(expirationDateRequired),
53
+ nonce,
54
+ metadata: '0x'
55
+ };
56
+
57
+ const domain = {
58
+ name: 'MCPayment',
59
+ version: '1.0.0',
60
+ chainId,
61
+ verifyingContract: paymentRails
62
+ };
63
+
64
+ const signature = await signer.signTypedData(domain, types, paymentData);
65
+
66
+ const proof: EthereumEip712Signature2021[] = [
67
+ {
68
+ type: SupportedPaymentProofType.EthereumEip712Signature2021,
69
+ proofPurpose: 'assertionMethod',
70
+ proofValue: signature,
71
+ verificationMethod: `did:pkh:eip155:${chainId}:${await signer.getAddress()}`,
72
+ created: new Date().toISOString(),
73
+ eip712: {
74
+ types: typeUrl,
75
+ primaryType: 'Iden3PaymentRailsRequestV1',
76
+ domain
77
+ }
78
+ }
79
+ ];
80
+ const d: Iden3PaymentRailsRequestV1 = {
81
+ type: PaymentRequestDataType.Iden3PaymentRailsRequestV1,
82
+ '@context': [
83
+ `https://schema.iden3.io/core/jsonld/payment.jsonld#${option.type}`,
84
+ 'https://w3id.org/security/suites/eip712sig-2021/v1'
85
+ ],
86
+ recipient,
87
+ amount: amount.toString(),
88
+ expirationDate: expirationDateRequired.toISOString(),
89
+ nonce: nonce.toString(),
90
+ metadata: '0x',
91
+ proof
92
+ };
93
+
94
+ if (option.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1) {
95
+ return d;
96
+ }
97
+ return {
98
+ ...d,
99
+ type: option.type,
100
+ tokenAddress: option.contractAddress || '',
101
+ features: option.features || []
102
+ } as Iden3PaymentRailsERC20RequestV1;
103
+ };
104
+
105
+ export async function verifyEIP712TypedData(
106
+ data: Iden3PaymentRailsRequestV1 | Iden3PaymentRailsERC20RequestV1,
107
+ resolver: Resolvable
108
+ ): Promise<string> {
109
+ const paymentData =
110
+ data.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
111
+ ? {
112
+ recipient: data.recipient,
113
+ amount: data.amount,
114
+ expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
115
+ nonce: data.nonce,
116
+ metadata: '0x'
117
+ }
118
+ : {
119
+ tokenAddress: data.tokenAddress,
120
+ recipient: data.recipient,
121
+ amount: data.amount,
122
+ expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
123
+ nonce: data.nonce,
124
+ metadata: '0x'
125
+ };
126
+ const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
127
+ const typesFetchResult = await fetch(proof.eip712.types);
128
+ const types = await typesFetchResult.json();
129
+ delete types.EIP712Domain;
130
+ const recovered = ethers.verifyTypedData(
131
+ proof.eip712.domain,
132
+ types,
133
+ paymentData,
134
+ proof.proofValue
135
+ );
136
+
137
+ const { didDocument } = await resolver.resolve(proof.verificationMethod);
138
+ if (didDocument?.verificationMethod) {
139
+ for (const verificationMethod of didDocument.verificationMethod) {
140
+ if (
141
+ verificationMethod.blockchainAccountId?.split(':').slice(-1)[0].toLowerCase() ===
142
+ recovered.toLowerCase()
143
+ ) {
144
+ return recovered;
145
+ }
146
+ }
147
+ } else {
148
+ throw new Error('failed request. issuer DIDDocument does not contain any verificationMethods');
149
+ }
150
+
151
+ throw new Error(`failed request. no matching verificationMethod`);
152
+ }