@0xpolygonid/js-sdk 1.21.3 → 1.24.1
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 +4378 -545
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +4388 -545
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/credentials/credential-wallet.js +11 -78
- package/dist/node/cjs/credentials/index.js +1 -0
- package/dist/node/cjs/credentials/status/did-resolver-revocation.js +21 -0
- package/dist/node/cjs/iden3comm/constants.js +25 -1
- package/dist/node/cjs/iden3comm/handlers/auth.js +52 -8
- package/dist/node/cjs/iden3comm/handlers/common.js +13 -1
- package/dist/node/cjs/iden3comm/handlers/contract-request.js +5 -1
- package/dist/node/cjs/iden3comm/handlers/credential-proposal.js +14 -3
- package/dist/node/cjs/iden3comm/handlers/fetch.js +44 -2
- package/dist/node/cjs/iden3comm/handlers/message-handler.js +4 -0
- package/dist/node/cjs/iden3comm/handlers/payment.js +265 -28
- package/dist/node/cjs/iden3comm/handlers/revocation-status.js +4 -0
- package/dist/node/cjs/iden3comm/index.js +1 -0
- package/dist/node/cjs/iden3comm/packageManager.js +12 -0
- package/dist/node/cjs/iden3comm/packers/jws.js +21 -0
- package/dist/node/cjs/iden3comm/packers/plain.js +19 -0
- package/dist/node/cjs/iden3comm/packers/zkp.js +25 -0
- package/dist/node/cjs/iden3comm/types/index.js +1 -0
- package/dist/node/cjs/iden3comm/types/protocol/accept-profile.js +2 -0
- package/dist/node/cjs/iden3comm/utils/accept-profile.js +107 -0
- package/dist/node/cjs/iden3comm/utils/index.js +1 -0
- package/dist/node/cjs/storage/blockchain/abi/ERC20.json +1 -0
- package/dist/node/cjs/storage/blockchain/abi/ERC20Permit.json +1 -0
- package/dist/node/cjs/storage/blockchain/did-resolver-readonly-storage.js +72 -0
- package/dist/node/cjs/storage/blockchain/erc20-helper.js +59 -0
- package/dist/node/cjs/storage/blockchain/index.js +3 -0
- package/dist/node/cjs/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.js +245 -0
- package/dist/node/cjs/storage/blockchain/onchain-issuer.js +82 -0
- package/dist/node/cjs/storage/blockchain/onchain-zkp-verifier.js +38 -34
- package/dist/node/cjs/storage/interfaces/index.js +1 -0
- package/dist/node/cjs/storage/interfaces/onchain-issuer.js +2 -0
- package/dist/node/cjs/utils/did-helper.js +3 -3
- package/dist/node/cjs/verifiable/constants.js +29 -11
- package/dist/node/cjs/verifiable/credential.js +86 -0
- package/dist/node/esm/credentials/credential-wallet.js +12 -79
- package/dist/node/esm/credentials/index.js +1 -0
- package/dist/node/esm/credentials/status/did-resolver-revocation.js +17 -0
- package/dist/node/esm/iden3comm/constants.js +24 -0
- package/dist/node/esm/iden3comm/handlers/auth.js +55 -11
- package/dist/node/esm/iden3comm/handlers/common.js +11 -0
- package/dist/node/esm/iden3comm/handlers/contract-request.js +7 -3
- package/dist/node/esm/iden3comm/handlers/credential-proposal.js +15 -4
- package/dist/node/esm/iden3comm/handlers/fetch.js +44 -2
- package/dist/node/esm/iden3comm/handlers/message-handler.js +4 -0
- package/dist/node/esm/iden3comm/handlers/payment.js +264 -29
- package/dist/node/esm/iden3comm/handlers/revocation-status.js +4 -0
- package/dist/node/esm/iden3comm/index.js +1 -0
- package/dist/node/esm/iden3comm/packageManager.js +12 -0
- package/dist/node/esm/iden3comm/packers/jws.js +22 -1
- package/dist/node/esm/iden3comm/packers/plain.js +19 -0
- package/dist/node/esm/iden3comm/packers/zkp.js +26 -1
- package/dist/node/esm/iden3comm/types/index.js +1 -0
- package/dist/node/esm/iden3comm/types/protocol/accept-profile.js +1 -0
- package/dist/node/esm/iden3comm/utils/accept-profile.js +102 -0
- package/dist/node/esm/iden3comm/utils/index.js +1 -0
- package/dist/node/esm/storage/blockchain/abi/ERC20.json +1 -0
- package/dist/node/esm/storage/blockchain/abi/ERC20Permit.json +1 -0
- package/dist/node/esm/storage/blockchain/did-resolver-readonly-storage.js +68 -0
- package/dist/node/esm/storage/blockchain/erc20-helper.js +51 -0
- package/dist/node/esm/storage/blockchain/index.js +3 -0
- package/dist/node/esm/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.js +241 -0
- package/dist/node/esm/storage/blockchain/onchain-issuer.js +78 -0
- package/dist/node/esm/storage/blockchain/onchain-zkp-verifier.js +38 -34
- package/dist/node/esm/storage/interfaces/index.js +1 -0
- package/dist/node/esm/storage/interfaces/onchain-issuer.js +1 -0
- package/dist/node/esm/utils/did-helper.js +3 -3
- package/dist/node/esm/verifiable/constants.js +28 -10
- package/dist/node/esm/verifiable/credential.js +88 -2
- package/dist/types/credentials/credential-wallet.d.ts +0 -6
- package/dist/types/credentials/index.d.ts +1 -0
- package/dist/types/credentials/models.d.ts +8 -0
- package/dist/types/credentials/status/did-resolver-revocation.d.ts +7 -0
- package/dist/types/iden3comm/constants.d.ts +16 -0
- package/dist/types/iden3comm/handlers/auth.d.ts +19 -7
- package/dist/types/iden3comm/handlers/common.d.ts +7 -1
- package/dist/types/iden3comm/handlers/contract-request.d.ts +2 -2
- package/dist/types/iden3comm/handlers/credential-proposal.d.ts +9 -4
- package/dist/types/iden3comm/handlers/fetch.d.ts +30 -6
- package/dist/types/iden3comm/handlers/message-handler.d.ts +6 -0
- package/dist/types/iden3comm/handlers/payment.d.ts +71 -10
- package/dist/types/iden3comm/handlers/revocation-status.d.ts +2 -2
- package/dist/types/iden3comm/index.d.ts +1 -0
- package/dist/types/iden3comm/packageManager.d.ts +4 -0
- package/dist/types/iden3comm/packers/jws.d.ts +5 -0
- package/dist/types/iden3comm/packers/plain.d.ts +4 -0
- package/dist/types/iden3comm/packers/zkp.d.ts +6 -0
- package/dist/types/iden3comm/types/index.d.ts +1 -0
- package/dist/types/iden3comm/types/packageManager.d.ts +14 -0
- package/dist/types/iden3comm/types/packer.d.ts +25 -0
- package/dist/types/iden3comm/types/protocol/accept-profile.d.ts +7 -0
- package/dist/types/iden3comm/types/protocol/auth.d.ts +1 -0
- package/dist/types/iden3comm/types/protocol/credentials.d.ts +6 -6
- package/dist/types/iden3comm/types/protocol/messages.d.ts +2 -2
- package/dist/types/iden3comm/types/protocol/payment.d.ts +87 -13
- package/dist/types/iden3comm/types/protocol/proof.d.ts +3 -3
- package/dist/types/iden3comm/types/protocol/revocation.d.ts +2 -2
- package/dist/types/iden3comm/utils/accept-profile.d.ts +3 -0
- package/dist/types/iden3comm/utils/index.d.ts +1 -0
- package/dist/types/storage/blockchain/did-resolver-readonly-storage.d.ts +16 -0
- package/dist/types/storage/blockchain/erc20-helper.d.ts +19 -0
- package/dist/types/storage/blockchain/index.d.ts +3 -0
- package/dist/types/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.d.ts +66 -0
- package/dist/types/storage/blockchain/onchain-issuer.d.ts +40 -0
- package/dist/types/storage/blockchain/onchain-zkp-verifier.d.ts +11 -12
- package/dist/types/storage/entities/state.d.ts +2 -0
- package/dist/types/storage/interfaces/index.d.ts +1 -0
- package/dist/types/storage/interfaces/onchain-issuer.d.ts +12 -0
- package/dist/types/verifiable/constants.d.ts +28 -11
- package/dist/types/verifiable/credential.d.ts +15 -2
- package/package.json +3 -2
|
@@ -7,6 +7,7 @@ import { proving } from '@iden3/js-jwz';
|
|
|
7
7
|
import { DID } from '@iden3/js-iden3-core';
|
|
8
8
|
import * as uuid from 'uuid';
|
|
9
9
|
import { AbstractMessageHandler } from './message-handler';
|
|
10
|
+
import { verifyExpiresTime } from './common';
|
|
10
11
|
/**
|
|
11
12
|
*
|
|
12
13
|
* Allows to handle Credential offer protocol message and return fetched credential
|
|
@@ -46,10 +47,34 @@ export class FetchHandler extends AbstractMessageHandler {
|
|
|
46
47
|
return this.handleFetchRequest(message);
|
|
47
48
|
case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE:
|
|
48
49
|
return this.handleIssuanceResponseMsg(message);
|
|
50
|
+
case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE: {
|
|
51
|
+
const result = await this.handleOnchainOfferMessage(message);
|
|
52
|
+
if (Array.isArray(result)) {
|
|
53
|
+
const credWallet = this.opts?.credentialWallet;
|
|
54
|
+
if (!credWallet)
|
|
55
|
+
throw new Error('Credential wallet is not provided');
|
|
56
|
+
await credWallet.saveAll(result);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
49
61
|
default:
|
|
50
62
|
return super.handle(message, ctx);
|
|
51
63
|
}
|
|
52
64
|
}
|
|
65
|
+
async handleOnchainOfferMessage(offerMessage) {
|
|
66
|
+
if (!this.opts?.onchainIssuer) {
|
|
67
|
+
throw new Error('onchain issuer is not provided');
|
|
68
|
+
}
|
|
69
|
+
const credentials = [];
|
|
70
|
+
for (const credentialInfo of offerMessage.body.credentials) {
|
|
71
|
+
const issuerDID = DID.parse(offerMessage.from);
|
|
72
|
+
const userDID = DID.parse(offerMessage.to);
|
|
73
|
+
const credential = await this.opts.onchainIssuer.getCredential(issuerDID, userDID, BigInt(credentialInfo.id));
|
|
74
|
+
credentials.push(credential);
|
|
75
|
+
}
|
|
76
|
+
return credentials;
|
|
77
|
+
}
|
|
53
78
|
async handleOfferMessage(offerMessage, ctx) {
|
|
54
79
|
if (!ctx.mediaType) {
|
|
55
80
|
ctx.mediaType = MediaType.ZKPMessage;
|
|
@@ -121,6 +146,9 @@ export class FetchHandler extends AbstractMessageHandler {
|
|
|
121
146
|
throw new Error(`jws packer options are required for ${MediaType.SignedMessage}`);
|
|
122
147
|
}
|
|
123
148
|
const offerMessage = await FetchHandler.unpackMessage(this._packerMgr, offer, PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE);
|
|
149
|
+
if (!opts?.allowExpiredMessages) {
|
|
150
|
+
verifyExpiresTime(offerMessage);
|
|
151
|
+
}
|
|
124
152
|
const result = await this.handleOfferMessage(offerMessage, {
|
|
125
153
|
mediaType: opts?.mediaType,
|
|
126
154
|
headers: opts?.headers,
|
|
@@ -131,6 +159,14 @@ export class FetchHandler extends AbstractMessageHandler {
|
|
|
131
159
|
}
|
|
132
160
|
throw new Error('invalid protocol message response');
|
|
133
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Handles only messages with credentials/1.0/onchain-offer type
|
|
164
|
+
* @beta
|
|
165
|
+
*/
|
|
166
|
+
async handleOnchainOffer(offer) {
|
|
167
|
+
const offerMessage = await FetchHandler.unpackMessage(this._packerMgr, offer, PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE);
|
|
168
|
+
return this.handleOnchainOfferMessage(offerMessage);
|
|
169
|
+
}
|
|
134
170
|
async handleFetchRequest(msgRequest) {
|
|
135
171
|
if (!msgRequest.to) {
|
|
136
172
|
throw new Error("failed request. empty 'to' field");
|
|
@@ -168,8 +204,11 @@ export class FetchHandler extends AbstractMessageHandler {
|
|
|
168
204
|
/**
|
|
169
205
|
* @inheritdoc IFetchHandler#handleCredentialFetchRequest
|
|
170
206
|
*/
|
|
171
|
-
async handleCredentialFetchRequest(envelope) {
|
|
207
|
+
async handleCredentialFetchRequest(envelope, opts) {
|
|
172
208
|
const msgRequest = await FetchHandler.unpackMessage(this._packerMgr, envelope, PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE);
|
|
209
|
+
if (!opts?.allowExpiredMessages) {
|
|
210
|
+
verifyExpiresTime(msgRequest);
|
|
211
|
+
}
|
|
173
212
|
const request = await this.handleFetchRequest(msgRequest);
|
|
174
213
|
return this._packerMgr.pack(MediaType.PlainMessage, byteEncoder.encode(JSON.stringify(request)), {});
|
|
175
214
|
}
|
|
@@ -186,8 +225,11 @@ export class FetchHandler extends AbstractMessageHandler {
|
|
|
186
225
|
/**
|
|
187
226
|
* @inheritdoc IFetchHandler#handleIssuanceResponseMessage
|
|
188
227
|
*/
|
|
189
|
-
async handleIssuanceResponseMessage(envelop) {
|
|
228
|
+
async handleIssuanceResponseMessage(envelop, opts) {
|
|
190
229
|
const issuanceMsg = await FetchHandler.unpackMessage(this._packerMgr, envelop, PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE);
|
|
230
|
+
if (!opts?.allowExpiredMessages) {
|
|
231
|
+
verifyExpiresTime(issuanceMsg);
|
|
232
|
+
}
|
|
191
233
|
await this.handleIssuanceResponseMsg(issuanceMsg);
|
|
192
234
|
return Uint8Array.from([]);
|
|
193
235
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MediaType } from '../constants';
|
|
2
2
|
import { proving } from '@iden3/js-jwz';
|
|
3
|
+
import { verifyExpiresTime } from './common';
|
|
3
4
|
/**
|
|
4
5
|
* Base implementation of protocol message handler
|
|
5
6
|
*
|
|
@@ -14,6 +15,9 @@ export class AbstractMessageHandler {
|
|
|
14
15
|
return messageHandler;
|
|
15
16
|
}
|
|
16
17
|
async handle(message, context) {
|
|
18
|
+
if (!context.allowExpiredMessages) {
|
|
19
|
+
verifyExpiresTime(message);
|
|
20
|
+
}
|
|
17
21
|
if (this.nextMessageHandler)
|
|
18
22
|
return this.nextMessageHandler.handle(message, context);
|
|
19
23
|
return Promise.reject('Message handler not provided or message not supported');
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { PROTOCOL_MESSAGE_TYPE } from '../constants';
|
|
2
2
|
import { MediaType } from '../constants';
|
|
3
|
-
import { DID } from '@iden3/js-iden3-core';
|
|
3
|
+
import { DID, getUnixTimestamp } from '@iden3/js-iden3-core';
|
|
4
4
|
import * as uuid from 'uuid';
|
|
5
5
|
import { proving } from '@iden3/js-jwz';
|
|
6
6
|
import { byteEncoder } from '../../utils';
|
|
7
7
|
import { AbstractMessageHandler } from './message-handler';
|
|
8
|
-
import {
|
|
8
|
+
import { PaymentFeatures, PaymentRequestDataType, PaymentType, SupportedCurrencies, SupportedPaymentProofType } from '../../verifiable';
|
|
9
|
+
import { ethers, parseEther, parseUnits } from 'ethers';
|
|
10
|
+
import { verifyExpiresTime } from './common';
|
|
9
11
|
/**
|
|
10
12
|
* @beta
|
|
11
13
|
* createPaymentRequest is a function to create protocol payment-request message
|
|
@@ -15,7 +17,7 @@ import { PaymentRequestDataType, PaymentRequestType, PaymentType } from '../../v
|
|
|
15
17
|
* @param {PaymentRequestInfo[]} payments - payments
|
|
16
18
|
* @returns `PaymentRequestMessage`
|
|
17
19
|
*/
|
|
18
|
-
export function createPaymentRequest(sender, receiver, agent, payments) {
|
|
20
|
+
export function createPaymentRequest(sender, receiver, agent, payments, opts) {
|
|
19
21
|
const uuidv4 = uuid.v4();
|
|
20
22
|
const request = {
|
|
21
23
|
id: uuidv4,
|
|
@@ -27,19 +29,82 @@ export function createPaymentRequest(sender, receiver, agent, payments) {
|
|
|
27
29
|
body: {
|
|
28
30
|
agent,
|
|
29
31
|
payments
|
|
30
|
-
}
|
|
32
|
+
},
|
|
33
|
+
created_time: getUnixTimestamp(new Date()),
|
|
34
|
+
expires_time: opts?.expires_time ? getUnixTimestamp(opts.expires_time) : undefined
|
|
31
35
|
};
|
|
32
36
|
return request;
|
|
33
37
|
}
|
|
38
|
+
export async function verifyEIP712TypedData(data, resolver) {
|
|
39
|
+
const convertedAmount = await convertPaymentAmount(data.amount, data.currency);
|
|
40
|
+
const paymentData = data.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
41
|
+
? {
|
|
42
|
+
recipient: data.recipient,
|
|
43
|
+
amount: convertedAmount,
|
|
44
|
+
expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
|
|
45
|
+
nonce: data.nonce,
|
|
46
|
+
metadata: '0x'
|
|
47
|
+
}
|
|
48
|
+
: {
|
|
49
|
+
tokenAddress: data.tokenAddress,
|
|
50
|
+
recipient: data.recipient,
|
|
51
|
+
amount: convertedAmount,
|
|
52
|
+
expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
|
|
53
|
+
nonce: data.nonce,
|
|
54
|
+
metadata: '0x'
|
|
55
|
+
};
|
|
56
|
+
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
57
|
+
const typesFetchResult = await fetch(proof.eip712.types);
|
|
58
|
+
const types = await typesFetchResult.json();
|
|
59
|
+
delete types.EIP712Domain;
|
|
60
|
+
const recovered = ethers.verifyTypedData(proof.eip712.domain, types, paymentData, proof.proofValue);
|
|
61
|
+
const { didDocument } = await resolver.resolve(proof.verificationMethod);
|
|
62
|
+
if (didDocument?.verificationMethod) {
|
|
63
|
+
for (const verificationMethod of didDocument.verificationMethod) {
|
|
64
|
+
if (verificationMethod.blockchainAccountId?.split(':').slice(-1)[0].toLowerCase() ===
|
|
65
|
+
recovered.toLowerCase()) {
|
|
66
|
+
return recovered;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw new Error('failed request. issuer DIDDocument does not contain any verificationMethods');
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`failed request. no matching verificationMethod`);
|
|
74
|
+
}
|
|
75
|
+
export async function convertPaymentAmount(amount, currency) {
|
|
76
|
+
let convertedAmount = 0n;
|
|
77
|
+
switch (currency) {
|
|
78
|
+
case SupportedCurrencies.ETH:
|
|
79
|
+
case SupportedCurrencies.POL:
|
|
80
|
+
case SupportedCurrencies.MATIC:
|
|
81
|
+
convertedAmount = parseEther(amount.toString());
|
|
82
|
+
break;
|
|
83
|
+
case SupportedCurrencies.ETH_WEI:
|
|
84
|
+
convertedAmount = parseUnits(amount.toString(), 'wei');
|
|
85
|
+
break;
|
|
86
|
+
case SupportedCurrencies.ETH_GWEI:
|
|
87
|
+
convertedAmount = parseUnits(amount.toString(), 'gwei');
|
|
88
|
+
break;
|
|
89
|
+
case SupportedCurrencies.USDC:
|
|
90
|
+
case SupportedCurrencies.USDT: {
|
|
91
|
+
convertedAmount = parseUnits(amount.toString(), 6);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
throw new Error(`failed request. unsupported currency ${currency}`);
|
|
96
|
+
}
|
|
97
|
+
return convertedAmount;
|
|
98
|
+
}
|
|
34
99
|
/**
|
|
35
100
|
* @beta
|
|
36
101
|
* createPayment is a function to create protocol payment message
|
|
37
102
|
* @param {DID} sender - sender did
|
|
38
103
|
* @param {DID} receiver - receiver did
|
|
39
|
-
* @param {
|
|
104
|
+
* @param {PaymentMessageBody} body - payments
|
|
40
105
|
* @returns `PaymentMessage`
|
|
41
106
|
*/
|
|
42
|
-
export function createPayment(sender, receiver, payments) {
|
|
107
|
+
export function createPayment(sender, receiver, payments, opts) {
|
|
43
108
|
const uuidv4 = uuid.v4();
|
|
44
109
|
const request = {
|
|
45
110
|
id: uuidv4,
|
|
@@ -50,7 +115,9 @@ export function createPayment(sender, receiver, payments) {
|
|
|
50
115
|
type: PROTOCOL_MESSAGE_TYPE.PAYMENT_MESSAGE_TYPE,
|
|
51
116
|
body: {
|
|
52
117
|
payments
|
|
53
|
-
}
|
|
118
|
+
},
|
|
119
|
+
created_time: getUnixTimestamp(new Date()),
|
|
120
|
+
expires_time: opts?.expires_time ? getUnixTimestamp(opts.expires_time) : undefined
|
|
54
121
|
};
|
|
55
122
|
return request;
|
|
56
123
|
}
|
|
@@ -112,21 +179,28 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
112
179
|
const receiverDID = DID.parse(paymentRequest.from);
|
|
113
180
|
const payments = [];
|
|
114
181
|
for (let i = 0; i < paymentRequest.body.payments.length; i++) {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
182
|
+
const { data } = paymentRequest.body.payments[i];
|
|
183
|
+
const selectedPayment = Array.isArray(data)
|
|
184
|
+
? data.find((p) => {
|
|
185
|
+
return p.type === PaymentRequestDataType.Iden3PaymentRequestCryptoV1
|
|
186
|
+
? p.id === ctx.nonce
|
|
187
|
+
: p.nonce === ctx.nonce;
|
|
188
|
+
})
|
|
189
|
+
: data;
|
|
190
|
+
if (!selectedPayment) {
|
|
191
|
+
throw new Error(`failed request. no payment in request for nonce ${ctx.nonce}`);
|
|
118
192
|
}
|
|
119
|
-
|
|
120
|
-
|
|
193
|
+
switch (selectedPayment.type) {
|
|
194
|
+
case PaymentRequestDataType.Iden3PaymentRequestCryptoV1:
|
|
195
|
+
payments.push(await this.handleIden3PaymentRequestCryptoV1(selectedPayment, ctx.paymentHandler));
|
|
196
|
+
break;
|
|
197
|
+
case PaymentRequestDataType.Iden3PaymentRailsRequestV1:
|
|
198
|
+
payments.push(await this.handleIden3PaymentRailsRequestV1(selectedPayment, ctx.paymentHandler));
|
|
199
|
+
break;
|
|
200
|
+
case PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1:
|
|
201
|
+
payments.push(await this.handleIden3PaymentRailsERC20RequestV1(selectedPayment, ctx.paymentHandler, ctx.erc20TokenApproveHandler));
|
|
202
|
+
break;
|
|
121
203
|
}
|
|
122
|
-
const txId = await ctx.paymentHandler(paymentReq.data);
|
|
123
|
-
payments.push({
|
|
124
|
-
id: paymentReq.data.id,
|
|
125
|
-
type: PaymentType.Iden3PaymentCryptoV1,
|
|
126
|
-
paymentData: {
|
|
127
|
-
txId
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
204
|
}
|
|
131
205
|
const paymentMessage = createPayment(senderDID, receiverDID, payments);
|
|
132
206
|
const response = await this.packMessage(paymentMessage, senderDID);
|
|
@@ -159,6 +233,9 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
159
233
|
if (!paymentRequest.to) {
|
|
160
234
|
throw new Error(`failed request. empty 'to' field`);
|
|
161
235
|
}
|
|
236
|
+
if (!opts?.allowExpiredMessages) {
|
|
237
|
+
verifyExpiresTime(paymentRequest);
|
|
238
|
+
}
|
|
162
239
|
const agentMessage = await this.handlePaymentRequestMessage(paymentRequest, opts);
|
|
163
240
|
if (!agentMessage) {
|
|
164
241
|
return null;
|
|
@@ -169,24 +246,121 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
169
246
|
/**
|
|
170
247
|
* @inheritdoc IPaymentHandler#handlePayment
|
|
171
248
|
*/
|
|
172
|
-
async handlePayment(payment,
|
|
173
|
-
if (
|
|
174
|
-
|
|
249
|
+
async handlePayment(payment, params) {
|
|
250
|
+
if (!params?.allowExpiredMessages) {
|
|
251
|
+
verifyExpiresTime(payment);
|
|
252
|
+
}
|
|
253
|
+
if (params.paymentRequest.from !== payment.to) {
|
|
254
|
+
throw new Error(`sender of the request is not a target of response - expected ${params.paymentRequest.from}, given ${payment.to}`);
|
|
175
255
|
}
|
|
176
256
|
if (!payment.body.payments.length) {
|
|
177
257
|
throw new Error(`failed request. empty 'payments' field in body`);
|
|
178
258
|
}
|
|
259
|
+
if (!params.paymentValidationHandler) {
|
|
260
|
+
throw new Error(`please provide payment validation handler in options`);
|
|
261
|
+
}
|
|
179
262
|
for (let i = 0; i < payment.body.payments.length; i++) {
|
|
180
263
|
const p = payment.body.payments[i];
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
264
|
+
const nonce = p.type === PaymentType.Iden3PaymentCryptoV1 ? p.id : p.nonce;
|
|
265
|
+
const requestDataArr = params.paymentRequest.body.payments
|
|
266
|
+
.map((r) => (Array.isArray(r.data) ? r.data : [r.data]))
|
|
267
|
+
.flat();
|
|
268
|
+
const requestData = requestDataArr.find((r) => r.type === PaymentRequestDataType.Iden3PaymentRequestCryptoV1
|
|
269
|
+
? r.id === nonce
|
|
270
|
+
: r.nonce === nonce);
|
|
271
|
+
if (!requestData) {
|
|
272
|
+
throw new Error(`can't find payment request for payment ${p.type === PaymentType.Iden3PaymentCryptoV1 ? 'id' : 'nonce'} ${nonce}`);
|
|
184
273
|
}
|
|
185
|
-
|
|
186
|
-
|
|
274
|
+
await params.paymentValidationHandler(p.paymentData.txId, requestData);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* @inheritdoc IPaymentHandler#createPaymentRailsV1
|
|
279
|
+
*/
|
|
280
|
+
async createPaymentRailsV1(sender, receiver, agent, signer, payments) {
|
|
281
|
+
const paymentRequestInfo = [];
|
|
282
|
+
for (let i = 0; i < payments.length; i++) {
|
|
283
|
+
const { credentials, description } = payments[i];
|
|
284
|
+
const dataArr = [];
|
|
285
|
+
for (let j = 0; j < payments[i].chains.length; j++) {
|
|
286
|
+
const { features, nonce, amount, currency, chainId, expirationDate, type } = payments[i].chains[j];
|
|
287
|
+
const multiChainConfig = this._params.multiChainPaymentConfig?.find((c) => c.chainId === chainId);
|
|
288
|
+
if (!multiChainConfig) {
|
|
289
|
+
throw new Error(`failed request. no config for chain ${chainId}`);
|
|
290
|
+
}
|
|
291
|
+
const { recipient, paymentContract, erc20TokenAddressArr } = multiChainConfig;
|
|
292
|
+
const tokenAddress = erc20TokenAddressArr.find((t) => t.symbol === currency)?.address;
|
|
293
|
+
if (type === PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1 && !tokenAddress) {
|
|
294
|
+
throw new Error(`failed request. no token address for currency ${currency}`);
|
|
295
|
+
}
|
|
296
|
+
const expirationDateRequired = expirationDate ?? new Date(new Date().setHours(new Date().getHours() + 1));
|
|
297
|
+
const typeUrl = `https://schema.iden3.io/core/json/${type}.json`;
|
|
298
|
+
const typesFetchResult = await fetch(typeUrl);
|
|
299
|
+
const types = await typesFetchResult.json();
|
|
300
|
+
delete types.EIP712Domain;
|
|
301
|
+
const convertedAmount = await convertPaymentAmount(amount, currency);
|
|
302
|
+
const paymentData = type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
303
|
+
? {
|
|
304
|
+
recipient,
|
|
305
|
+
amount: convertedAmount,
|
|
306
|
+
expirationDate: getUnixTimestamp(expirationDateRequired),
|
|
307
|
+
nonce,
|
|
308
|
+
metadata: '0x'
|
|
309
|
+
}
|
|
310
|
+
: {
|
|
311
|
+
tokenAddress,
|
|
312
|
+
recipient,
|
|
313
|
+
amount: convertedAmount,
|
|
314
|
+
expirationDate: getUnixTimestamp(expirationDateRequired),
|
|
315
|
+
nonce,
|
|
316
|
+
metadata: '0x'
|
|
317
|
+
};
|
|
318
|
+
const domain = {
|
|
319
|
+
name: 'MCPayment',
|
|
320
|
+
version: '1.0.0',
|
|
321
|
+
chainId,
|
|
322
|
+
verifyingContract: paymentContract
|
|
323
|
+
};
|
|
324
|
+
const signature = await signer.signTypedData(domain, types, paymentData);
|
|
325
|
+
const proof = [
|
|
326
|
+
{
|
|
327
|
+
type: SupportedPaymentProofType.EthereumEip712Signature2021,
|
|
328
|
+
proofPurpose: 'assertionMethod',
|
|
329
|
+
proofValue: signature,
|
|
330
|
+
verificationMethod: `did:pkh:eip155:${chainId}:${await signer.getAddress()}`,
|
|
331
|
+
created: new Date().toISOString(),
|
|
332
|
+
eip712: {
|
|
333
|
+
types: typeUrl,
|
|
334
|
+
primaryType: 'Iden3PaymentRailsRequestV1',
|
|
335
|
+
domain
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
];
|
|
339
|
+
const d = {
|
|
340
|
+
type: PaymentRequestDataType.Iden3PaymentRailsRequestV1,
|
|
341
|
+
'@context': [
|
|
342
|
+
`https://schema.iden3.io/core/jsonld/payment.jsonld#${type}`,
|
|
343
|
+
'https://w3id.org/security/suites/eip712sig-2021/v1'
|
|
344
|
+
],
|
|
345
|
+
recipient,
|
|
346
|
+
amount: amount.toString(),
|
|
347
|
+
currency,
|
|
348
|
+
expirationDate: expirationDateRequired.toISOString(),
|
|
349
|
+
nonce: nonce.toString(),
|
|
350
|
+
metadata: '0x',
|
|
351
|
+
proof
|
|
352
|
+
};
|
|
353
|
+
dataArr.push(type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
354
|
+
? d
|
|
355
|
+
: { ...d, type, tokenAddress: tokenAddress || '', features: features || [] });
|
|
187
356
|
}
|
|
188
|
-
|
|
357
|
+
paymentRequestInfo.push({
|
|
358
|
+
data: dataArr,
|
|
359
|
+
credentials,
|
|
360
|
+
description
|
|
361
|
+
});
|
|
189
362
|
}
|
|
363
|
+
return createPaymentRequest(sender, receiver, agent, paymentRequestInfo);
|
|
190
364
|
}
|
|
191
365
|
async packMessage(message, senderDID) {
|
|
192
366
|
const responseEncoded = byteEncoder.encode(JSON.stringify(message));
|
|
@@ -200,4 +374,65 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
200
374
|
...packerOpts
|
|
201
375
|
});
|
|
202
376
|
}
|
|
377
|
+
async handleIden3PaymentRequestCryptoV1(data, paymentHandler) {
|
|
378
|
+
if (data.expiration && new Date(data.expiration) < new Date()) {
|
|
379
|
+
throw new Error(`failed request. expired request`);
|
|
380
|
+
}
|
|
381
|
+
const txId = await paymentHandler(data);
|
|
382
|
+
return {
|
|
383
|
+
id: data.id,
|
|
384
|
+
'@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentCryptoV1',
|
|
385
|
+
type: PaymentType.Iden3PaymentCryptoV1,
|
|
386
|
+
paymentData: {
|
|
387
|
+
txId
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
async handleIden3PaymentRailsRequestV1(data, paymentHandler) {
|
|
392
|
+
if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
|
|
393
|
+
throw new Error(`failed request. expired request`);
|
|
394
|
+
}
|
|
395
|
+
const signer = await verifyEIP712TypedData(data, this._params.documentResolver);
|
|
396
|
+
if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
|
|
397
|
+
throw new Error(`failed request. signer is not in the allowed signers list`);
|
|
398
|
+
}
|
|
399
|
+
const txId = await paymentHandler(data);
|
|
400
|
+
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
401
|
+
return {
|
|
402
|
+
nonce: data.nonce,
|
|
403
|
+
type: PaymentType.Iden3PaymentRailsV1,
|
|
404
|
+
'@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsV1',
|
|
405
|
+
paymentData: {
|
|
406
|
+
txId,
|
|
407
|
+
chainId: proof.eip712.domain.chainId
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
async handleIden3PaymentRailsERC20RequestV1(data, paymentHandler, approveHandler) {
|
|
412
|
+
if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
|
|
413
|
+
throw new Error(`failed request. expired request`);
|
|
414
|
+
}
|
|
415
|
+
const signer = await verifyEIP712TypedData(data, this._params.documentResolver);
|
|
416
|
+
if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
|
|
417
|
+
throw new Error(`failed request. signer is not in the allowed signers list`);
|
|
418
|
+
}
|
|
419
|
+
if (!data.features?.includes(PaymentFeatures.EIP_2612) && !approveHandler) {
|
|
420
|
+
throw new Error(`please provide erc20TokenApproveHandler in context for ERC-20 payment type`);
|
|
421
|
+
}
|
|
422
|
+
if (approveHandler) {
|
|
423
|
+
await approveHandler(data);
|
|
424
|
+
}
|
|
425
|
+
const txId = await paymentHandler(data);
|
|
426
|
+
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
427
|
+
return {
|
|
428
|
+
nonce: data.nonce,
|
|
429
|
+
type: PaymentType.Iden3PaymentRailsERC20V1,
|
|
430
|
+
'@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsERC20V1',
|
|
431
|
+
paymentData: {
|
|
432
|
+
txId,
|
|
433
|
+
chainId: proof.eip712.domain.chainId,
|
|
434
|
+
tokenAddress: data.tokenAddress
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
}
|
|
203
438
|
}
|
|
@@ -5,6 +5,7 @@ import * as uuid from 'uuid';
|
|
|
5
5
|
import { byteEncoder } from '../../utils';
|
|
6
6
|
import { proving } from '@iden3/js-jwz';
|
|
7
7
|
import { AbstractMessageHandler } from './message-handler';
|
|
8
|
+
import { verifyExpiresTime } from './common';
|
|
8
9
|
/**
|
|
9
10
|
*
|
|
10
11
|
* Allows to process RevocationStatusRequest protocol message
|
|
@@ -97,6 +98,9 @@ export class RevocationStatusHandler extends AbstractMessageHandler {
|
|
|
97
98
|
throw new Error(`jws packer options are required for ${MediaType.SignedMessage}`);
|
|
98
99
|
}
|
|
99
100
|
const rsRequest = await this.parseRevocationStatusRequest(request);
|
|
101
|
+
if (!opts.allowExpiredMessages) {
|
|
102
|
+
verifyExpiresTime(rsRequest);
|
|
103
|
+
}
|
|
100
104
|
const response = await this.handleRevocationStatusRequestMessage(rsRequest, {
|
|
101
105
|
senderDid: did,
|
|
102
106
|
mediaType: opts.mediaType,
|
|
@@ -15,6 +15,18 @@ export class PackageManager {
|
|
|
15
15
|
constructor() {
|
|
16
16
|
this.packers = new Map();
|
|
17
17
|
}
|
|
18
|
+
/** {@inheritDoc IPackageManager.isProfileSupported} */
|
|
19
|
+
isProfileSupported(mediaType, profile) {
|
|
20
|
+
const p = this.packers.get(mediaType);
|
|
21
|
+
if (!p) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return p.isProfileSupported(profile);
|
|
25
|
+
}
|
|
26
|
+
/** {@inheritDoc IPackageManager.getSupportedMediaTypes} */
|
|
27
|
+
getSupportedMediaTypes() {
|
|
28
|
+
return [...this.packers.keys()];
|
|
29
|
+
}
|
|
18
30
|
/** {@inheritDoc IPackageManager.registerPackers} */
|
|
19
31
|
registerPackers(packers) {
|
|
20
32
|
packers.forEach((p) => {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants';
|
|
1
|
+
import { AcceptJwsAlgorithms, MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants';
|
|
2
2
|
import { extractPublicKeyBytes, resolveVerificationMethods } from '../utils/did';
|
|
3
3
|
import { keyPath } from '../../kms/';
|
|
4
4
|
import { verifyJWS } from 'did-jwt';
|
|
5
5
|
import { parse } from 'did-resolver';
|
|
6
6
|
import { bytesToBase64url } from '../../utils/encoding';
|
|
7
7
|
import { byteDecoder, byteEncoder, bytesToHex, decodeBase64url, encodeBase64url } from '../../utils';
|
|
8
|
+
import { parseAcceptProfile } from '../utils';
|
|
8
9
|
/**
|
|
9
10
|
* Packer that can pack message to JWZ token,
|
|
10
11
|
* and unpack and validate JWZ envelope
|
|
@@ -83,6 +84,26 @@ export class JWSPacker {
|
|
|
83
84
|
mediaType() {
|
|
84
85
|
return MediaType.SignedMessage;
|
|
85
86
|
}
|
|
87
|
+
/** {@inheritDoc IPacker.getSupportedProfiles} */
|
|
88
|
+
getSupportedProfiles() {
|
|
89
|
+
return [`env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(',')}`];
|
|
90
|
+
}
|
|
91
|
+
/** {@inheritDoc IPacker.isProfileSupported} */
|
|
92
|
+
isProfileSupported(profile) {
|
|
93
|
+
const { env, circuits, alg } = parseAcceptProfile(profile);
|
|
94
|
+
if (env !== this.mediaType()) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (circuits) {
|
|
98
|
+
throw new Error(`Circuits are not supported for ${env} media type`);
|
|
99
|
+
}
|
|
100
|
+
const supportedAlgArr = this.getSupportedAlgorithms();
|
|
101
|
+
const algSupported = !alg?.length || alg.some((a) => supportedAlgArr.includes(a));
|
|
102
|
+
return algSupported;
|
|
103
|
+
}
|
|
104
|
+
getSupportedAlgorithms() {
|
|
105
|
+
return [AcceptJwsAlgorithms.ES256K, AcceptJwsAlgorithms.ES256KR];
|
|
106
|
+
}
|
|
86
107
|
async resolveDidDoc(from) {
|
|
87
108
|
let didDocument;
|
|
88
109
|
try {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MediaType } from '../constants';
|
|
2
2
|
import { byteDecoder, byteEncoder } from '../../utils';
|
|
3
|
+
import { parseAcceptProfile } from '../utils';
|
|
3
4
|
/**
|
|
4
5
|
* Plain packer just serializes bytes to JSON and adds media type
|
|
5
6
|
*
|
|
@@ -49,4 +50,22 @@ export class PlainPacker {
|
|
|
49
50
|
mediaType() {
|
|
50
51
|
return MediaType.PlainMessage;
|
|
51
52
|
}
|
|
53
|
+
/** {@inheritDoc IPacker.getSupportedProfiles} */
|
|
54
|
+
getSupportedProfiles() {
|
|
55
|
+
return [`env=${this.mediaType()}`];
|
|
56
|
+
}
|
|
57
|
+
/** {@inheritDoc IPacker.isProfileSupported} */
|
|
58
|
+
isProfileSupported(profile) {
|
|
59
|
+
const { env, circuits, alg } = parseAcceptProfile(profile);
|
|
60
|
+
if (env !== this.mediaType()) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (circuits) {
|
|
64
|
+
throw new Error(`Circuits are not supported for ${env} media type`);
|
|
65
|
+
}
|
|
66
|
+
if (alg) {
|
|
67
|
+
throw new Error(`Algorithms are not supported for ${env} media type`);
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
52
71
|
}
|
|
@@ -3,9 +3,10 @@ import { AuthV2PubSignals, CircuitId } from '../../circuits/index';
|
|
|
3
3
|
import { BytesHelper, DID } from '@iden3/js-iden3-core';
|
|
4
4
|
import { bytesToProtocolMessage } from '../utils/envelope';
|
|
5
5
|
import { ErrNoProvingMethodAlg, ErrPackedWithUnsupportedCircuit, ErrProofIsInvalid, ErrSenderNotUsedTokenCreation, ErrStateVerificationFailed, ErrUnknownCircuitID } from '../errors';
|
|
6
|
-
import { MediaType } from '../constants';
|
|
6
|
+
import { AcceptAuthCircuits, AcceptJwzAlgorithms, MediaType } from '../constants';
|
|
7
7
|
import { byteDecoder, byteEncoder } from '../../utils';
|
|
8
8
|
import { DEFAULT_AUTH_VERIFY_DELAY } from '../constants';
|
|
9
|
+
import { parseAcceptProfile } from '../utils';
|
|
9
10
|
const { getProvingMethod } = proving;
|
|
10
11
|
/**
|
|
11
12
|
* Handler to
|
|
@@ -136,6 +137,30 @@ export class ZKPPacker {
|
|
|
136
137
|
mediaType() {
|
|
137
138
|
return MediaType.ZKPMessage;
|
|
138
139
|
}
|
|
140
|
+
/** {@inheritDoc IPacker.getSupportedProfiles} */
|
|
141
|
+
getSupportedProfiles() {
|
|
142
|
+
return [
|
|
143
|
+
`env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(',')}&circuitIds=${this.getSupportedCircuitIds().join(',')}`
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
/** {@inheritDoc IPacker.isProfileSupported} */
|
|
147
|
+
isProfileSupported(profile) {
|
|
148
|
+
const { env, circuits, alg } = parseAcceptProfile(profile);
|
|
149
|
+
if (env !== this.mediaType()) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
const supportedCircuitIds = this.getSupportedCircuitIds();
|
|
153
|
+
const circuitIdSupported = !circuits?.length || circuits.some((c) => supportedCircuitIds.includes(c));
|
|
154
|
+
const supportedAlgArr = this.getSupportedAlgorithms();
|
|
155
|
+
const algSupported = !alg?.length || alg.some((a) => supportedAlgArr.includes(a));
|
|
156
|
+
return algSupported && circuitIdSupported;
|
|
157
|
+
}
|
|
158
|
+
getSupportedAlgorithms() {
|
|
159
|
+
return [AcceptJwzAlgorithms.Groth16];
|
|
160
|
+
}
|
|
161
|
+
getSupportedCircuitIds() {
|
|
162
|
+
return [AcceptAuthCircuits.AuthV2];
|
|
163
|
+
}
|
|
139
164
|
}
|
|
140
165
|
const verifySender = async (token, msg) => {
|
|
141
166
|
switch (token.circuitId) {
|
|
@@ -6,6 +6,7 @@ export * from './protocol/revocation';
|
|
|
6
6
|
export * from './protocol/contract-request';
|
|
7
7
|
export * from './protocol/proposal-request';
|
|
8
8
|
export * from './protocol/payment';
|
|
9
|
+
export * from './protocol/accept-profile';
|
|
9
10
|
export * from './packer';
|
|
10
11
|
export * from './models';
|
|
11
12
|
export * from './packageManager';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|