Skip to content

Commit 65abe13

Browse files
add handlePayment logic and move txParams
1 parent 75ba0d2 commit 65abe13

File tree

2 files changed

+126
-60
lines changed

2 files changed

+126
-60
lines changed

src/iden3comm/handlers/payment.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,7 @@ export interface IPaymentHandler {
109109
payment: PaymentMessage;
110110
}>`
111111
*/
112-
handlePayment(
113-
payment: PaymentMessage,
114-
opts?: PaymentHandlerOptions
115-
): Promise<{
116-
payment: PaymentMessage;
117-
}>;
112+
handlePayment(payment: PaymentMessage, opts: PaymentHandlerOptions): Promise<void>;
118113
}
119114

120115
/** @beta PaymentRequestMessageHandlerOptions represents payment-request handler options */
@@ -124,12 +119,14 @@ export type PaymentTxData = ContractInvokeTransactionData & {
124119

125120
/** @beta PaymentRequestMessageHandlerOptions represents payment-request handler options */
126121
export type PaymentRequestMessageHandlerOptions = {
127-
paymentHandler: (data: PaymentRequestDataInfo) => Promise<string>;
122+
txParams: unknown[];
123+
paymentHandler: (data: PaymentRequestDataInfo, txParams: unknown[]) => Promise<string>;
128124
};
129125

130126
/** @beta PaymentHandlerOptions represents payment handler options */
131127
export type PaymentHandlerOptions = {
132-
paymentRequest?: PaymentRequestMessage;
128+
paymentRequest: PaymentRequestMessage;
129+
checkPaymentHandler: (txId: string, data: PaymentRequestDataInfo) => Promise<void>;
133130
};
134131

135132
/** @beta PaymentHandlerParams represents payment handler params */
@@ -218,7 +215,7 @@ export class PaymentHandler
218215
throw new Error(`failed request. not supported '${paymentReq.data.type}' payment type `);
219216
}
220217

221-
const txID = await ctx.paymentHandler(paymentReq.data);
218+
const txID = await ctx.paymentHandler(paymentReq.data, ctx.txParams);
222219
payments.push({
223220
id: paymentReq.data.id,
224221
type: PaymentType.Iden3PaymentCryptoV1,
@@ -261,6 +258,8 @@ export class PaymentHandler
261258
provingMethodAlg: proving.provingMethodGroth16AuthV2Instance.methodAlg
262259
};
263260

261+
// send to agent, return void
262+
264263
return this._packerMgr.pack(this._params.packerParams.mediaType, response, {
265264
senderDID,
266265
...packerOpts
@@ -270,12 +269,24 @@ export class PaymentHandler
270269
/**
271270
* @inheritdoc IPaymentHandler#handlePayment
272271
*/
273-
async handlePayment(payment: PaymentMessage, opts?: PaymentHandlerOptions) {
274-
if (opts?.paymentRequest && opts.paymentRequest.from !== payment.to) {
272+
async handlePayment(payment: PaymentMessage, opts: PaymentHandlerOptions) {
273+
if (opts.paymentRequest && opts.paymentRequest.from !== payment.to) {
275274
throw new Error(
276275
`sender of the request is not a target of response - expected ${opts.paymentRequest.from}, given ${payment.to}`
277276
);
278277
}
279-
return { payment };
278+
279+
if (!payment.body?.payments.length) {
280+
throw new Error(`failed request. empty 'payments' field in body`);
281+
}
282+
283+
for (let i = 0; i < payment.body.payments.length; i++) {
284+
const p = payment.body?.payments[i];
285+
const paymentRequestData = opts.paymentRequest.body?.payments.find((r) => r.data.id === p.id);
286+
if (!paymentRequestData) {
287+
throw new Error(`can't find payment request for payment id ${p.id}`);
288+
}
289+
await opts.checkPaymentHandler(p.paymentData.txID, paymentRequestData.data);
290+
}
280291
}
281292
}

tests/handlers/payment.test.ts

Lines changed: 103 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -50,58 +50,71 @@ describe('payment-request handler', () => {
5050
const packageManager: IPackageManager = new PackageManager();
5151
packageManager.registerPackers([new PlainPacker()]);
5252

53-
const paymentIntegrationHandlerFunc = async (data: PaymentRequestDataInfo): Promise<string> => {
54-
const counterContractAbi = [
55-
{
56-
inputs: [
57-
{
58-
internalType: 'string',
59-
name: '',
60-
type: 'string'
61-
}
62-
],
63-
name: 'Payments',
64-
outputs: [
65-
{
66-
internalType: 'string',
67-
name: 'issuerIdHash',
68-
type: 'string'
69-
}
70-
],
71-
stateMutability: 'view',
72-
type: 'function'
73-
},
74-
{
75-
inputs: [
76-
{
77-
internalType: 'string',
78-
name: 'sessionIdHash',
79-
type: 'string'
80-
},
81-
{
82-
internalType: 'string',
83-
name: 'issuerIdHash',
84-
type: 'string'
85-
}
86-
],
87-
name: 'pay',
88-
outputs: [],
89-
stateMutability: 'payable',
90-
type: 'function'
91-
}
92-
];
53+
const payContractAbi = [
54+
{
55+
inputs: [
56+
{
57+
internalType: 'string',
58+
name: '',
59+
type: 'string'
60+
}
61+
],
62+
name: 'Payments',
63+
outputs: [
64+
{
65+
internalType: 'string',
66+
name: 'issuerIdHash',
67+
type: 'string'
68+
}
69+
],
70+
stateMutability: 'view',
71+
type: 'function'
72+
},
73+
{
74+
inputs: [
75+
{
76+
internalType: 'string',
77+
name: 'sessionIdHash',
78+
type: 'string'
79+
},
80+
{
81+
internalType: 'string',
82+
name: 'issuerIdHash',
83+
type: 'string'
84+
}
85+
],
86+
name: 'pay',
87+
outputs: [],
88+
stateMutability: 'payable',
89+
type: 'function'
90+
}
91+
];
92+
93+
const paymentIntegrationHandlerFunc = async (
94+
data: PaymentRequestDataInfo,
95+
txParams: unknown[]
96+
): Promise<string> => {
9397
const rpcProvider = new JsonRpcProvider(RPC_URL);
9498
const ethSigner = new ethers.Wallet(WALLET_KEY, rpcProvider);
95-
const payContract = new Contract(data.address, counterContractAbi, ethSigner);
99+
const payContract = new Contract(data.address, payContractAbi, ethSigner);
96100
const options = { value: data.amount };
97-
const txData = await payContract.pay(
98-
ethers.hashMessage('<sessionidhere>'),
99-
ethers.hashMessage('<issuer_did_here>'),
100-
options
101-
);
101+
const txData = await payContract.pay(...txParams, options);
102102
return txData.hash;
103103
};
104104

105+
const paymentCheckIntegrationHandlerFunc = async (
106+
txId: string,
107+
data: PaymentRequestDataInfo
108+
): Promise<void> => {
109+
const rpcProvider = new JsonRpcProvider(RPC_URL);
110+
111+
const tx = await rpcProvider.getTransaction(txId);
112+
113+
if (tx?.value !== BigInt(data.amount)) {
114+
throw new Error('invalid value');
115+
}
116+
};
117+
105118
const paymentReqInfo: PaymentRequestInfo = {
106119
credentials: [
107120
{
@@ -173,7 +186,8 @@ describe('payment-request handler', () => {
173186
{}
174187
);
175188
const paymentMessageBytes = await paymentHandler.handlePaymentRequest(msgBytesRequest, {
176-
paymentHandler: paymentUnitHandlerFunc
189+
paymentHandler: paymentUnitHandlerFunc,
190+
txParams: ['<session-id-hash>', '<issuer-did-hash>']
177191
});
178192
const { unpackedMessage: paymentMessage } = await packageManager.unpack(paymentMessageBytes);
179193

@@ -184,6 +198,27 @@ describe('payment-request handler', () => {
184198
expect((paymentMessage as PaymentMessage).body?.payments[0].paymentData.txID).to.be.not.empty;
185199
});
186200

201+
it('payment handler', async () => {
202+
const paymentRequest = createPaymentRequest(userDID, issuerDID, [paymentReqInfo]);
203+
const msgBytesRequest = await packageManager.pack(
204+
MediaType.PlainMessage,
205+
byteEncoder.encode(JSON.stringify(paymentRequest)),
206+
{}
207+
);
208+
const paymentMessageBytes = await paymentHandler.handlePaymentRequest(msgBytesRequest, {
209+
paymentHandler: paymentUnitHandlerFunc,
210+
txParams: ['<session-id-hash>', '<issuer-did-hash>']
211+
});
212+
const { unpackedMessage: paymentMessage } = await packageManager.unpack(paymentMessageBytes);
213+
214+
paymentHandler.handlePayment(paymentMessage as PaymentMessage, {
215+
paymentRequest,
216+
checkPaymentHandler: async () => {
217+
Promise.resolve();
218+
}
219+
});
220+
});
221+
187222
it.skip('payment-request handler (integration test)', async () => {
188223
const paymentRequest = createPaymentRequest(userDID, issuerDID, [paymentReqInfo]);
189224
const msgBytesRequest = await packageManager.pack(
@@ -192,7 +227,8 @@ describe('payment-request handler', () => {
192227
{}
193228
);
194229
const paymentMessageBytes = await paymentHandler.handlePaymentRequest(msgBytesRequest, {
195-
paymentHandler: paymentIntegrationHandlerFunc
230+
paymentHandler: paymentIntegrationHandlerFunc,
231+
txParams: ['<session-id-hash>', '<issuer-did-hash>']
196232
});
197233
const { unpackedMessage: paymentMessage } = await packageManager.unpack(paymentMessageBytes);
198234

@@ -202,4 +238,23 @@ describe('payment-request handler', () => {
202238

203239
expect((paymentMessage as PaymentMessage).body?.payments[0].paymentData.txID).to.be.not.empty;
204240
});
241+
242+
it.skip('payment handler (integration test)', async () => {
243+
const paymentRequest = createPaymentRequest(userDID, issuerDID, [paymentReqInfo]);
244+
const msgBytesRequest = await packageManager.pack(
245+
MediaType.PlainMessage,
246+
byteEncoder.encode(JSON.stringify(paymentRequest)),
247+
{}
248+
);
249+
const paymentMessageBytes = await paymentHandler.handlePaymentRequest(msgBytesRequest, {
250+
paymentHandler: paymentIntegrationHandlerFunc,
251+
txParams: ['<session-id-hash>', '<issuer-did-hash>']
252+
});
253+
const { unpackedMessage: paymentMessage } = await packageManager.unpack(paymentMessageBytes);
254+
255+
paymentHandler.handlePayment(paymentMessage as PaymentMessage, {
256+
paymentRequest,
257+
checkPaymentHandler: paymentCheckIntegrationHandlerFunc
258+
});
259+
});
205260
});

0 commit comments

Comments
 (0)