@0xpolygonid/js-sdk 1.33.0 → 1.33.3
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/browser/esm/index.js +1123 -719
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.global.js +182 -59
- package/dist/browser/umd/index.global.js.map +1 -1
- package/dist/node/cjs/index.cjs +1330 -915
- package/dist/node/cjs/index.cjs.map +1 -1
- package/dist/node/esm/index.js +1123 -719
- package/dist/node/esm/index.js.map +1 -1
- package/dist/types/iden3comm/handlers/credential-proposal.d.ts.map +1 -1
- package/dist/types/iden3comm/handlers/fetch.d.ts.map +1 -1
- package/dist/types/iden3comm/handlers/payment.d.ts +14 -5
- package/dist/types/iden3comm/handlers/payment.d.ts.map +1 -1
- package/dist/types/iden3comm/types/protocol/payment.d.ts +58 -9
- package/dist/types/iden3comm/types/protocol/payment.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/payments/evm.d.ts +19 -0
- package/dist/types/utils/payments/evm.d.ts.map +1 -0
- package/dist/types/utils/payments/solana.d.ts +88 -0
- package/dist/types/utils/payments/solana.d.ts.map +1 -0
- package/dist/types/verifiable/constants.d.ts +16 -3
- package/dist/types/verifiable/constants.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/iden3comm/handlers/credential-proposal.ts +4 -1
- package/src/iden3comm/handlers/fetch.ts +7 -1
- package/src/iden3comm/handlers/payment.ts +138 -131
- package/src/iden3comm/types/protocol/payment.ts +79 -10
- package/src/utils/index.ts +2 -0
- package/src/utils/payments/evm.ts +152 -0
- package/src/utils/payments/solana.ts +360 -0
- package/src/verifiable/constants.ts +17 -3
|
@@ -5,18 +5,21 @@ import { BasicMessage, IPackageManager, PackerParams } from '../types';
|
|
|
5
5
|
import { DID, getUnixTimestamp } from '@iden3/js-iden3-core';
|
|
6
6
|
import * as uuid from 'uuid';
|
|
7
7
|
import { proving } from '@iden3/js-jwz';
|
|
8
|
-
import { byteEncoder } from '../../utils';
|
|
8
|
+
import { buildSolanaPayment, byteEncoder, verifyIden3SolanaPaymentRequest } from '../../utils';
|
|
9
9
|
import {
|
|
10
10
|
AbstractMessageHandler,
|
|
11
11
|
BasicHandlerOptions,
|
|
12
12
|
IProtocolMessageHandler
|
|
13
13
|
} from './message-handler';
|
|
14
14
|
import {
|
|
15
|
-
EthereumEip712Signature2021,
|
|
16
15
|
Iden3PaymentCryptoV1,
|
|
17
16
|
Iden3PaymentRailsERC20RequestV1,
|
|
18
17
|
Iden3PaymentRailsERC20V1,
|
|
19
18
|
Iden3PaymentRailsRequestV1,
|
|
19
|
+
Iden3PaymentRailsSolanaRequestV1,
|
|
20
|
+
Iden3PaymentRailsSolanaSPLRequestV1,
|
|
21
|
+
Iden3PaymentRailsSolanaSPLV1,
|
|
22
|
+
Iden3PaymentRailsSolanaV1,
|
|
20
23
|
Iden3PaymentRailsV1,
|
|
21
24
|
Iden3PaymentRequestCryptoV1,
|
|
22
25
|
MultiChainPaymentConfig,
|
|
@@ -26,15 +29,12 @@ import {
|
|
|
26
29
|
PaymentRequestTypeUnion,
|
|
27
30
|
PaymentTypeUnion
|
|
28
31
|
} from '../types/protocol/payment';
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
PaymentRequestDataType,
|
|
32
|
-
PaymentType,
|
|
33
|
-
SupportedPaymentProofType
|
|
34
|
-
} from '../../verifiable';
|
|
35
|
-
import { Signer, ethers } from 'ethers';
|
|
32
|
+
import { PaymentFeatures, PaymentRequestDataType, PaymentType } from '../../verifiable';
|
|
33
|
+
import { Signer } from 'ethers';
|
|
36
34
|
import { Resolvable } from 'did-resolver';
|
|
37
35
|
import { verifyExpiresTime } from './common';
|
|
36
|
+
import { Keypair } from '@solana/web3.js';
|
|
37
|
+
import { buildEvmPayment, verifyEIP712TypedData } from '../../utils/payments/evm';
|
|
38
38
|
|
|
39
39
|
/** @beta PaymentRequestCreationOptions represents payment-request creation options */
|
|
40
40
|
export type PaymentRequestCreationOptions = {
|
|
@@ -46,6 +46,12 @@ export type PaymentCreationOptions = {
|
|
|
46
46
|
expires_time?: Date;
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
+
/** @beta CreatePaymentRailsV1Options holds options for PaymentRailsV1 creation */
|
|
50
|
+
export type CreatePaymentRailsV1Options = {
|
|
51
|
+
ethSigner?: Signer;
|
|
52
|
+
solSigner?: Keypair;
|
|
53
|
+
};
|
|
54
|
+
|
|
49
55
|
/**
|
|
50
56
|
* @beta
|
|
51
57
|
* createPaymentRequest is a function to create protocol payment-request message
|
|
@@ -80,55 +86,6 @@ export function createPaymentRequest(
|
|
|
80
86
|
return request;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
|
-
export async function verifyEIP712TypedData(
|
|
84
|
-
data: Iden3PaymentRailsRequestV1 | Iden3PaymentRailsERC20RequestV1,
|
|
85
|
-
resolver: Resolvable
|
|
86
|
-
): Promise<string> {
|
|
87
|
-
const paymentData =
|
|
88
|
-
data.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
89
|
-
? {
|
|
90
|
-
recipient: data.recipient,
|
|
91
|
-
amount: data.amount,
|
|
92
|
-
expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
|
|
93
|
-
nonce: data.nonce,
|
|
94
|
-
metadata: '0x'
|
|
95
|
-
}
|
|
96
|
-
: {
|
|
97
|
-
tokenAddress: data.tokenAddress,
|
|
98
|
-
recipient: data.recipient,
|
|
99
|
-
amount: data.amount,
|
|
100
|
-
expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
|
|
101
|
-
nonce: data.nonce,
|
|
102
|
-
metadata: '0x'
|
|
103
|
-
};
|
|
104
|
-
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
105
|
-
const typesFetchResult = await fetch(proof.eip712.types);
|
|
106
|
-
const types = await typesFetchResult.json();
|
|
107
|
-
delete types.EIP712Domain;
|
|
108
|
-
const recovered = ethers.verifyTypedData(
|
|
109
|
-
proof.eip712.domain,
|
|
110
|
-
types,
|
|
111
|
-
paymentData,
|
|
112
|
-
proof.proofValue
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
const { didDocument } = await resolver.resolve(proof.verificationMethod);
|
|
116
|
-
if (didDocument?.verificationMethod) {
|
|
117
|
-
for (const verificationMethod of didDocument.verificationMethod) {
|
|
118
|
-
if (
|
|
119
|
-
verificationMethod.blockchainAccountId?.split(':').slice(-1)[0].toLowerCase() ===
|
|
120
|
-
recovered.toLowerCase()
|
|
121
|
-
) {
|
|
122
|
-
return recovered;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
} else {
|
|
126
|
-
throw new Error('failed request. issuer DIDDocument does not contain any verificationMethods');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
throw new Error(`failed request. no matching verificationMethod`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
89
|
/**
|
|
133
90
|
* @beta
|
|
134
91
|
* PaymentRailsInfo represents payment info for payment rails
|
|
@@ -227,16 +184,18 @@ export interface IPaymentHandler {
|
|
|
227
184
|
* @param {DID} sender - sender did
|
|
228
185
|
* @param {DID} receiver - receiver did
|
|
229
186
|
* @param {string} agent - agent URL
|
|
230
|
-
* @param {Signer} signer -
|
|
187
|
+
* @param {Signer} signer - ETH signer
|
|
231
188
|
* @param payments - payment options
|
|
189
|
+
* @param {CreatePaymentRailsV1Options} createOptions - options for payment rails creation
|
|
232
190
|
* @returns {Promise<PaymentRequestMessage>}
|
|
233
191
|
*/
|
|
234
192
|
createPaymentRailsV1(
|
|
235
193
|
sender: DID,
|
|
236
194
|
receiver: DID,
|
|
237
195
|
agent: string,
|
|
238
|
-
signer: Signer,
|
|
239
|
-
payments: PaymentRailsInfo[]
|
|
196
|
+
signer: Signer, // the same as createOptions.ethSigner (for compatibility)
|
|
197
|
+
payments: PaymentRailsInfo[],
|
|
198
|
+
createOptions?: CreatePaymentRailsV1Options
|
|
240
199
|
): Promise<PaymentRequestMessage>;
|
|
241
200
|
}
|
|
242
201
|
|
|
@@ -380,6 +339,22 @@ export class PaymentHandler
|
|
|
380
339
|
)
|
|
381
340
|
);
|
|
382
341
|
break;
|
|
342
|
+
case PaymentRequestDataType.Iden3PaymentRailsSolanaRequestV1:
|
|
343
|
+
payments.push(
|
|
344
|
+
await this.handleIden3PaymentRailsSolanaRequestV1(selectedPayment, ctx.paymentHandler)
|
|
345
|
+
);
|
|
346
|
+
break;
|
|
347
|
+
case PaymentRequestDataType.Iden3PaymentRailsSolanaSPLRequestV1:
|
|
348
|
+
payments.push(
|
|
349
|
+
await this.handleIden3PaymentRailsSolanaSPLRequestV1(
|
|
350
|
+
{
|
|
351
|
+
...selectedPayment,
|
|
352
|
+
type: PaymentRequestDataType.Iden3PaymentRailsSolanaSPLRequestV1
|
|
353
|
+
},
|
|
354
|
+
ctx.paymentHandler
|
|
355
|
+
)
|
|
356
|
+
);
|
|
357
|
+
break;
|
|
383
358
|
}
|
|
384
359
|
}
|
|
385
360
|
|
|
@@ -490,12 +465,18 @@ export class PaymentHandler
|
|
|
490
465
|
receiver: DID,
|
|
491
466
|
agent: string,
|
|
492
467
|
signer: Signer,
|
|
493
|
-
payments: PaymentRailsInfo[]
|
|
468
|
+
payments: PaymentRailsInfo[],
|
|
469
|
+
createOptions?: CreatePaymentRailsV1Options
|
|
494
470
|
): Promise<PaymentRequestMessage> {
|
|
495
471
|
const paymentRequestInfo: PaymentRequestInfo[] = [];
|
|
496
472
|
for (let i = 0; i < payments.length; i++) {
|
|
497
473
|
const { credentials, description } = payments[i];
|
|
498
|
-
const dataArr: (
|
|
474
|
+
const dataArr: (
|
|
475
|
+
| Iden3PaymentRailsRequestV1
|
|
476
|
+
| Iden3PaymentRailsERC20RequestV1
|
|
477
|
+
| Iden3PaymentRailsSolanaRequestV1
|
|
478
|
+
| Iden3PaymentRailsSolanaSPLRequestV1
|
|
479
|
+
)[] = [];
|
|
499
480
|
for (let j = 0; j < payments[i].options.length; j++) {
|
|
500
481
|
const { nonce, amount, chainId, optionId, expirationDate } = payments[i].options[j];
|
|
501
482
|
|
|
@@ -512,82 +493,51 @@ export class PaymentHandler
|
|
|
512
493
|
throw new Error(`failed request. no option for id ${optionId}`);
|
|
513
494
|
}
|
|
514
495
|
if (
|
|
515
|
-
option.type === PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1
|
|
496
|
+
(option.type === PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1 ||
|
|
497
|
+
option.type === PaymentRequestDataType.Iden3PaymentRailsSolanaSPLRequestV1) &&
|
|
516
498
|
!option.contractAddress
|
|
517
499
|
) {
|
|
518
500
|
throw new Error(`failed request. no token address for option id ${optionId}`);
|
|
519
501
|
}
|
|
520
502
|
const expirationDateRequired =
|
|
521
503
|
expirationDate ?? new Date(new Date().setHours(new Date().getHours() + 1));
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
amount: amount,
|
|
532
|
-
expirationDate: getUnixTimestamp(expirationDateRequired),
|
|
533
|
-
nonce,
|
|
534
|
-
metadata: '0x'
|
|
535
|
-
}
|
|
536
|
-
: {
|
|
537
|
-
tokenAddress: option.contractAddress,
|
|
538
|
-
recipient,
|
|
539
|
-
amount: amount,
|
|
540
|
-
expirationDate: getUnixTimestamp(expirationDateRequired),
|
|
541
|
-
nonce,
|
|
542
|
-
metadata: '0x'
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
const domain = {
|
|
546
|
-
name: 'MCPayment',
|
|
547
|
-
version: '1.0.0',
|
|
548
|
-
chainId,
|
|
549
|
-
verifyingContract: paymentRails
|
|
550
|
-
};
|
|
551
|
-
const signature = await signer.signTypedData(domain, types, paymentData);
|
|
552
|
-
const proof: EthereumEip712Signature2021[] = [
|
|
553
|
-
{
|
|
554
|
-
type: SupportedPaymentProofType.EthereumEip712Signature2021,
|
|
555
|
-
proofPurpose: 'assertionMethod',
|
|
556
|
-
proofValue: signature,
|
|
557
|
-
verificationMethod: `did:pkh:eip155:${chainId}:${await signer.getAddress()}`,
|
|
558
|
-
created: new Date().toISOString(),
|
|
559
|
-
eip712: {
|
|
560
|
-
types: typeUrl,
|
|
561
|
-
primaryType: 'Iden3PaymentRailsRequestV1',
|
|
562
|
-
domain
|
|
563
|
-
}
|
|
504
|
+
|
|
505
|
+
if (
|
|
506
|
+
option.type === PaymentRequestDataType.Iden3PaymentRailsSolanaRequestV1 ||
|
|
507
|
+
option.type === PaymentRequestDataType.Iden3PaymentRailsSolanaSPLRequestV1
|
|
508
|
+
) {
|
|
509
|
+
if (!createOptions?.solSigner) {
|
|
510
|
+
throw new Error(
|
|
511
|
+
`please provide solana signer in context for ${option.type} payment type`
|
|
512
|
+
);
|
|
564
513
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
514
|
+
|
|
515
|
+
const payment = await buildSolanaPayment(
|
|
516
|
+
createOptions.solSigner,
|
|
517
|
+
option,
|
|
518
|
+
chainId,
|
|
519
|
+
paymentRails,
|
|
520
|
+
recipient,
|
|
521
|
+
BigInt(amount),
|
|
522
|
+
expirationDateRequired,
|
|
523
|
+
nonce
|
|
524
|
+
);
|
|
525
|
+
dataArr.push(payment);
|
|
526
|
+
} else {
|
|
527
|
+
const payment = await buildEvmPayment(
|
|
528
|
+
signer,
|
|
529
|
+
option,
|
|
530
|
+
chainId,
|
|
531
|
+
paymentRails,
|
|
532
|
+
recipient,
|
|
533
|
+
BigInt(amount),
|
|
534
|
+
expirationDateRequired,
|
|
535
|
+
nonce
|
|
536
|
+
);
|
|
537
|
+
dataArr.push(payment);
|
|
538
|
+
}
|
|
590
539
|
}
|
|
540
|
+
|
|
591
541
|
paymentRequestInfo.push({
|
|
592
542
|
data: dataArr,
|
|
593
543
|
credentials,
|
|
@@ -654,6 +604,63 @@ export class PaymentHandler
|
|
|
654
604
|
};
|
|
655
605
|
}
|
|
656
606
|
|
|
607
|
+
private async handleIden3PaymentRailsSolanaRequestV1(
|
|
608
|
+
data: Iden3PaymentRailsSolanaRequestV1,
|
|
609
|
+
paymentHandler: (data: Iden3PaymentRailsSolanaRequestV1) => Promise<string>
|
|
610
|
+
): Promise<Iden3PaymentRailsSolanaV1> {
|
|
611
|
+
if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
|
|
612
|
+
throw new Error(`failed request. expired request`);
|
|
613
|
+
}
|
|
614
|
+
const isValid = await verifyIden3SolanaPaymentRequest(data, this._params.documentResolver);
|
|
615
|
+
if (!isValid) {
|
|
616
|
+
throw new Error(`failed request. invalid Solana payment request signature`);
|
|
617
|
+
}
|
|
618
|
+
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
619
|
+
const signer = proof.verificationMethod.split(':').slice(-1)[0];
|
|
620
|
+
if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
|
|
621
|
+
throw new Error(`failed request. signer is not in the allowed signers list`);
|
|
622
|
+
}
|
|
623
|
+
const txId = await paymentHandler(data);
|
|
624
|
+
return {
|
|
625
|
+
nonce: data.nonce,
|
|
626
|
+
type: PaymentType.Iden3PaymentRailsSolanaV1,
|
|
627
|
+
'@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsSolanaV1',
|
|
628
|
+
paymentData: {
|
|
629
|
+
txId,
|
|
630
|
+
chainId: proof.domain.chainId
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
private async handleIden3PaymentRailsSolanaSPLRequestV1(
|
|
636
|
+
data: Iden3PaymentRailsSolanaSPLRequestV1,
|
|
637
|
+
paymentHandler: (data: Iden3PaymentRailsSolanaSPLRequestV1) => Promise<string>
|
|
638
|
+
): Promise<Iden3PaymentRailsSolanaSPLV1> {
|
|
639
|
+
if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
|
|
640
|
+
throw new Error(`failed request. expired request`);
|
|
641
|
+
}
|
|
642
|
+
const isValid = await verifyIden3SolanaPaymentRequest(data, this._params.documentResolver);
|
|
643
|
+
if (!isValid) {
|
|
644
|
+
throw new Error(`failed request. invalid Solana payment request signature`);
|
|
645
|
+
}
|
|
646
|
+
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
647
|
+
const signer = proof.verificationMethod.split(':').slice(-1)[0];
|
|
648
|
+
if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
|
|
649
|
+
throw new Error(`failed request. signer is not in the allowed signers list`);
|
|
650
|
+
}
|
|
651
|
+
const txId = await paymentHandler(data);
|
|
652
|
+
return {
|
|
653
|
+
nonce: data.nonce,
|
|
654
|
+
type: PaymentType.Iden3PaymentRailsSolanaSPLV1,
|
|
655
|
+
'@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsSolanaSPLV1',
|
|
656
|
+
paymentData: {
|
|
657
|
+
txId,
|
|
658
|
+
chainId: proof.domain.chainId,
|
|
659
|
+
tokenAddress: data.tokenAddress
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
|
|
657
664
|
private async handleIden3PaymentRailsERC20RequestV1(
|
|
658
665
|
data: Iden3PaymentRailsERC20RequestV1,
|
|
659
666
|
paymentHandler: (data: Iden3PaymentRailsERC20RequestV1) => Promise<string>,
|
|
@@ -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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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;
|
package/src/utils/index.ts
CHANGED
|
@@ -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
|
+
}
|