Skip to content

Commit

Permalink
Add logs payments related logs
Browse files Browse the repository at this point in the history
  • Loading branch information
prathamesh0 committed Jul 20, 2023
1 parent abef04d commit 74c2443
Showing 1 changed file with 33 additions and 12 deletions.
45 changes: 33 additions & 12 deletions packages/util/src/payments.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import debug from 'debug';
import { ethers } from 'ethers';
import { LRUCache } from 'lru-cache';
import { FieldNode } from 'graphql';
Expand All @@ -10,10 +11,13 @@ import type { Client, Signature, Voucher } from '@cerc-io/nitro-client';
import { recoverEthereumMessageSigner, getSignatureFromEthersSignature } from '@cerc-io/nitro-client';
import { hex2Bytes } from '@cerc-io/nitro-util';

const log = debug('laconic:payments');

const IntrospectionQuery = 'IntrospectionQuery';
const HASH_HEADER_KEY = 'hash';
const SIG_HEADER_KEY = 'sig';

const ERR_FREE_QUOTA_EXHUASTED = 'Free quota exhausted';
const ERR_PAYMENT_NOT_RECEIVED = 'Payment not received';
const HTTP_CODE_PAYMENT_NOT_RECEIVED = 402; // Payment required

Expand Down Expand Up @@ -50,6 +54,7 @@ export class PaymentsManager {

async subscribeToVouchers (client: Client): Promise<void> {
const receivedVouchersChannel = client.receivedVouchers();
log('Starting voucher subscription...');

while (true) {
switch (await Channel.select([
Expand All @@ -59,11 +64,13 @@ export class PaymentsManager {
case receivedVouchersChannel: {
const voucher = receivedVouchersChannel.value();
if (voucher === undefined) {
log('Voucher channel closed, stopping voucher subscription');
return;
}

const associatedPaymentChannel = await client.getPaymentChannel(voucher.channelId);
const payer = associatedPaymentChannel.balance.payer;
log(`Received a payment voucher from ${payer}`);

let vouchersMap = this.receivedVouchers.get(payer);
if (!vouchersMap) {
Expand All @@ -80,6 +87,7 @@ export class PaymentsManager {
}

case this.stopSubscriptionLoop:
log('Stop signal received, stopping voucher subscription');
return;
}
}
Expand All @@ -89,7 +97,7 @@ export class PaymentsManager {
await this.stopSubscriptionLoop.close();
}

async allowRequest (voucherHash: string, voucherSig: string): Promise<boolean> {
async allowRequest (voucherHash: string, voucherSig: string): Promise<[boolean, string]> {
const senderAddress = getSenderAddress(voucherHash, voucherSig);

if (voucherHash === EMPTY_VOUCHER_HASH) {
Expand All @@ -100,13 +108,26 @@ export class PaymentsManager {

// Check if user has exhausted their free query limit
if (remainingFreeQueries > 0) {
log(`Serving a free query for ${senderAddress}`);
this.remainingFreeQueriesMap.set(senderAddress, remainingFreeQueries - 1);
return true;

return [true, ''];
}

log(`Rejecting query from ${senderAddress}, user has exhausted their free quota`);
return [false, ERR_FREE_QUOTA_EXHUASTED];
}

// Check for payment voucher received from the Nitro account
return this.authenticateVoucherForSender(voucherHash, senderAddress);
const paymentVoucherRecived = await this.authenticateVoucherForSender(voucherHash, senderAddress);

if (paymentVoucherRecived) {
log(`Serving a paid query for ${senderAddress}`);
return [true, ''];
} else {
log(`Rejecting query from ${senderAddress}, payment voucher not received`);
return [false, ERR_PAYMENT_NOT_RECEIVED];
}
}

private async authenticateVoucherForSender (voucherHash:string, senderAddress: string): Promise<boolean> {
Expand Down Expand Up @@ -156,16 +177,16 @@ export const paymentsPlugin = (paymentsManager?: PaymentsManager): ApolloServerP
for await (const querySelection of querySelections ?? []) {
// TODO: Charge according to the querySelection

const failResponse: GraphQLResponse = {
errors: [{ message: ERR_PAYMENT_NOT_RECEIVED }],
http: new HTTPResponse(undefined, {
headers: requestContext.response?.http?.headers,
status: HTTP_CODE_PAYMENT_NOT_RECEIVED
})
};

const allowRequest = await paymentsManager.allowRequest(hash, sig);
const [allowRequest, rejectionMessage] = await paymentsManager.allowRequest(hash, sig);
if (!allowRequest) {
const failResponse: GraphQLResponse = {
errors: [{ message: rejectionMessage }],
http: new HTTPResponse(undefined, {
headers: requestContext.response?.http?.headers,
status: HTTP_CODE_PAYMENT_NOT_RECEIVED
})
};

return failResponse;
}
}
Expand Down

0 comments on commit 74c2443

Please sign in to comment.