Skip to content

Commit

Permalink
init Iden3PaymentRailsRequestV1
Browse files Browse the repository at this point in the history
  • Loading branch information
volodymyr-basiuk committed Oct 1, 2024
1 parent a33feb4 commit 80cf68e
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = {
...spellcheckerRule,
cspell: {
...cspellConfig,
ignoreWords: ['unmarshal', 'JUvpllMEYUZ2joO59UNui_XYDqxVqiFLLAJ8klWuPBw', 'gdwj', 'fwor']
ignoreWords: ['unmarshal', 'JUvpllMEYUZ2joO59UNui_XYDqxVqiFLLAJ8klWuPBw', 'gdwj', 'fwor', 'multichain']
}
}
]
Expand Down
111 changes: 96 additions & 15 deletions src/iden3comm/handlers/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import { proving } from '@iden3/js-jwz';
import { byteEncoder } from '../../utils';
import { AbstractMessageHandler, IProtocolMessageHandler } from './message-handler';
import {
PaymentInfo,
Iden3PaymentCryptoV1,
Iden3PaymentRailsRequestV1,
Iden3PaymentRailsResponseV1,
Iden3PaymentRequestCryptoV1,
PaymentMessage,
PaymentRequestDataInfo,
PaymentMessageBody,
PaymentRequestInfo,
PaymentRequestMessage
} from '../types/protocol/payment';
Expand Down Expand Up @@ -52,10 +55,14 @@ export function createPaymentRequest(
* createPayment is a function to create protocol payment message
* @param {DID} sender - sender did
* @param {DID} receiver - receiver did
* @param {PaymentInfo[]} payments - payments
* @param {PaymentMessageBody} body - payments
* @returns `PaymentMessage`
*/
export function createPayment(sender: DID, receiver: DID, payments: PaymentInfo[]): PaymentMessage {
export function createPayment(
sender: DID,
receiver: DID,
body: PaymentMessageBody
): PaymentMessage {
const uuidv4 = uuid.v4();
const request: PaymentMessage = {
id: uuidv4,
Expand All @@ -64,9 +71,7 @@ export function createPayment(sender: DID, receiver: DID, payments: PaymentInfo[
to: receiver.string(),
typ: MediaType.PlainMessage,
type: PROTOCOL_MESSAGE_TYPE.PAYMENT_MESSAGE_TYPE,
body: {
payments
}
body
};
return request;
}
Expand Down Expand Up @@ -110,13 +115,19 @@ export interface IPaymentHandler {

/** @beta PaymentRequestMessageHandlerOptions represents payment-request handler options */
export type PaymentRequestMessageHandlerOptions = {
paymentHandler: (data: PaymentRequestDataInfo) => Promise<string>;
paymentHandler: (
data: Iden3PaymentRequestCryptoV1 | Iden3PaymentRailsRequestV1
) => Promise<string>;
multichainSelectedChainId?: string;
};

/** @beta PaymentHandlerOptions represents payment handler options */
export type PaymentHandlerOptions = {
paymentRequest: PaymentRequestMessage;
paymentValidationHandler: (txId: string, data: PaymentRequestDataInfo) => Promise<void>;
paymentValidationHandler: (
txId: string,
data: Iden3PaymentRequestCryptoV1 | Iden3PaymentRailsRequestV1
) => Promise<void>;
};

/** @beta PaymentHandlerParams represents payment handler params */
Expand Down Expand Up @@ -202,13 +213,54 @@ export class PaymentHandler
const senderDID = DID.parse(paymentRequest.to);
const receiverDID = DID.parse(paymentRequest.from);

const payments: PaymentInfo[] = [];
const payments: (Iden3PaymentCryptoV1 | Iden3PaymentRailsResponseV1)[] = [];
for (let i = 0; i < paymentRequest.body.payments.length; i++) {
const paymentReq = paymentRequest.body.payments[i];
if (paymentReq.type !== PaymentRequestType.PaymentRequest) {
throw new Error(`failed request. not supported '${paymentReq.type}' payment type `);
}

// if multichain request
if (Array.isArray(paymentReq.data)) {
if (!ctx.multichainSelectedChainId) {
throw new Error(`failed request. no selected chain id`);
}

const selectedPayment = paymentReq.data.find((p) => {
const proofs = Array.isArray(p.proof) ? p.proof : [p.proof];
const eip712Signature2021Proof = proofs.filter(
(p) => p.type === 'EthereumEip712Signature2021'
)[0];
if (!eip712Signature2021Proof) {
return false;
}
return eip712Signature2021Proof.eip712.domain.chainId === ctx.multichainSelectedChainId;
});

if (!selectedPayment) {
throw new Error(
`failed request. no payment in request for chain id ${ctx.multichainSelectedChainId}`
);
}

if (selectedPayment.type !== PaymentRequestDataType.Iden3PaymentRailsRequestV1) {
throw new Error(`failed request. not supported '${selectedPayment.type}' payment type `);
}

const txId = await ctx.paymentHandler(selectedPayment);

payments.push({
nonce: selectedPayment.nonce,
type: PaymentType.Iden3PaymentRailsResponseV1,
paymentData: {
txId,
chainId: ctx.multichainSelectedChainId
}
});

continue;
}

if (paymentReq.data.type !== PaymentRequestDataType.Iden3PaymentRequestCryptoV1) {
throw new Error(`failed request. not supported '${paymentReq.data.type}' payment type `);
}
Expand All @@ -224,7 +276,7 @@ export class PaymentHandler
});
}

const paymentMessage = createPayment(senderDID, receiverDID, payments);
const paymentMessage = createPayment(senderDID, receiverDID, { payments });
const response = await this.packMessage(paymentMessage, senderDID);

const agentResult = await fetch(paymentRequest.body.agent, {
Expand Down Expand Up @@ -291,14 +343,43 @@ export class PaymentHandler

for (let i = 0; i < payment.body.payments.length; i++) {
const p = payment.body.payments[i];
const paymentRequestData = opts.paymentRequest.body.payments.find((r) => r.data.id === p.id);
if (!paymentRequestData) {
throw new Error(`can't find payment request for payment id ${p.id}`);
let data: Iden3PaymentRequestCryptoV1 | Iden3PaymentRailsRequestV1 | undefined;
switch (p.type) {
case PaymentType.Iden3PaymentCryptoV1: {
data = opts.paymentRequest.body.payments.find(
(r) => (r.data as Iden3PaymentRequestCryptoV1).id === p.id
)?.data as Iden3PaymentRequestCryptoV1;
if (!data) {
throw new Error(`can't find payment request for payment id ${p.id}`);
}
break;
}
case PaymentType.Iden3PaymentRailsResponseV1: {
for (let j = 0; j < opts.paymentRequest.body.payments.length; j++) {
const paymentReq = opts.paymentRequest.body.payments[j];
if (Array.isArray(paymentReq.data)) {
const selectedPayment = paymentReq.data.find(
(r) => (r as Iden3PaymentRailsRequestV1).nonce === p.nonce
) as Iden3PaymentRailsRequestV1;
if (selectedPayment) {
data = selectedPayment;
break;
}
}
}

if (!data) {
throw new Error(`can't find payment request for payment nonce ${p.nonce}`);
}
break;
}
default:
throw new Error(`failed request. not supported '${p.type}' payment type `);
}
if (!opts.paymentValidationHandler) {
throw new Error(`please provide payment validation handler in options`);
}
await opts.paymentValidationHandler(p.paymentData.txId, paymentRequestData.data);
await opts.paymentValidationHandler(p.paymentData.txId, data);
}
}

Expand Down
62 changes: 48 additions & 14 deletions src/iden3comm/types/protocol/payment.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { BasicMessage } from '../';
import {
PaymentRequestDataType,
PaymentRequestType,
PaymentType,
SupportedCurrencies
} from '../../../verifiable';
import { PaymentRequestType, SupportedCurrencies } from '../../../verifiable';
import { PROTOCOL_MESSAGE_TYPE } from '../../constants';

/** @beta PaymentRequestMessage is struct the represents payment-request message */
Expand All @@ -26,14 +21,14 @@ export type PaymentRequestInfo = {
context: string;
}[];
type: PaymentRequestType;
data: PaymentRequestDataInfo;
data: Iden3PaymentRequestCryptoV1 | Iden3PaymentRailsRequestV1[];
expiration?: string;
description?: string;
};

/** @beta PaymentRequestDataInfo is struct the represents payment data info for payment-request */
export type PaymentRequestDataInfo = {
type: PaymentRequestDataType;
/** @beta Iden3PaymentRequestCryptoV1 is struct the represents payment data info for payment-request */
export type Iden3PaymentRequestCryptoV1 = {
type: 'Iden3PaymentRequestCryptoV1';
amount: string;
id: string;
chainId: string;
Expand All @@ -42,6 +37,35 @@ export type PaymentRequestDataInfo = {
signature?: string;
};

export type Iden3PaymentRailsRequestV1 = {
type: 'Iden3PaymentRailsRequestV1';
recipient: string;
value: string;
expirationDate: string;
nonce: string;
metadata: string;
proof: EthereumEip712Signature2021 | EthereumEip712Signature2021[];
};

export type EthereumEip712Signature2021 = {
type: 'EthereumEip712Signature2021';
proofPurpose: string;
proofValue: string;
verificationMethod: string;
created: string;
eip712: {
types: string;
primaryType: string;
domain: {
name: string;
version: string;
chainId: string;
verifyingContract: string;
salt: string;
};
};
};

/** @beta PaymentMessage is struct the represents payment message */
export type PaymentMessage = BasicMessage & {
body: PaymentMessageBody;
Expand All @@ -50,14 +74,24 @@ export type PaymentMessage = BasicMessage & {

/** @beta PaymentMessageBody is struct the represents body for payment message */
export type PaymentMessageBody = {
payments: PaymentInfo[];
payments: (Iden3PaymentCryptoV1 | Iden3PaymentRailsResponseV1)[];
};

/** @beta PaymentInfo is struct the represents payment info for payment */
export type PaymentInfo = {
/** @beta Iden3PaymentCryptoV1 is struct the represents payment info for payment */
export type Iden3PaymentCryptoV1 = {
id: string;
type: PaymentType;
type: 'Iden3PaymentCryptoV1';
paymentData: {
txId: string;
};
};

/** @beta Iden3PaymentRailsResponseV1 is struct the represents payment info for Iden3PaymentRailsRequestV1 */
export type Iden3PaymentRailsResponseV1 = {
nonce: string;
type: 'Iden3PaymentRailsResponseV1';
paymentData: {
txId: string;
chainId: string;
};
};
6 changes: 4 additions & 2 deletions src/verifiable/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ export enum PaymentRequestType {
* @enum {string}
*/
export enum PaymentRequestDataType {
Iden3PaymentRequestCryptoV1 = 'Iden3PaymentRequestCryptoV1'
Iden3PaymentRequestCryptoV1 = 'Iden3PaymentRequestCryptoV1',
Iden3PaymentRailsRequestV1 = 'Iden3PaymentRailsRequestV1'
}

/**
Expand All @@ -137,7 +138,8 @@ export enum PaymentRequestDataType {
* @enum {string}
*/
export enum PaymentType {
Iden3PaymentCryptoV1 = 'Iden3PaymentCryptoV1'
Iden3PaymentCryptoV1 = 'Iden3PaymentCryptoV1',
Iden3PaymentRailsResponseV1 = 'Iden3PaymentRailsResponseV1'
}

/**
Expand Down
Loading

0 comments on commit 80cf68e

Please sign in to comment.