Skip to content

Commit

Permalink
add amount convertion and fix expirationDate (unix not ISO string)
Browse files Browse the repository at this point in the history
  • Loading branch information
volodymyr-basiuk committed Dec 2, 2024
1 parent 335d198 commit 6ee11ed
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 60 deletions.
63 changes: 48 additions & 15 deletions src/iden3comm/handlers/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
SupportedCurrencies,
SupportedPaymentProofType
} from '../../verifiable';
import { Signer, ethers } from 'ethers';
import { Signer, ethers, parseEther, parseUnits } from 'ethers';
import { Resolvable } from 'did-resolver';
import { verifyExpiresTime } from './common';

Expand Down Expand Up @@ -85,20 +85,24 @@ export async function verifyEIP712TypedData(
data: Iden3PaymentRailsRequestV1 | Iden3PaymentRailsERC20RequestV1,
resolver: Resolvable
): Promise<string> {
const convertedAmount = await convertPaymentAmount(
data.amount,
data.currency as SupportedCurrencies
);
const paymentData =
data.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
? {
recipient: data.recipient,
amount: data.amount,
expirationDate: new Date(data.expirationDate).getTime(),
amount: convertedAmount,
expirationDate: data.expirationDate,
nonce: data.nonce,
metadata: '0x'
}
: {
tokenAddress: data.tokenAddress,
recipient: data.recipient,
amount: data.amount,
expirationDate: new Date(data.expirationDate).getTime(),
amount: convertedAmount,
expirationDate: data.expirationDate,
nonce: data.nonce,
metadata: '0x'
};
Expand Down Expand Up @@ -130,6 +134,34 @@ export async function verifyEIP712TypedData(
throw new Error(`failed request. no matching verificationMethod`);
}

export async function convertPaymentAmount(
amount: string,
currency: SupportedCurrencies
): Promise<bigint> {
let convertedAmount = 0n;
switch (currency) {
case SupportedCurrencies.ETH:
case SupportedCurrencies.POL:
case SupportedCurrencies.MATIC:
convertedAmount = parseEther(amount.toString());
break;
case SupportedCurrencies.ETH_WEI:
convertedAmount = parseUnits(amount.toString(), 'wei');
break;
case SupportedCurrencies.ETH_GWEI:
convertedAmount = parseUnits(amount.toString(), 'gwei');
break;
case SupportedCurrencies.USDC:
case SupportedCurrencies.USDT: {
convertedAmount = parseUnits(amount.toString(), 6);
break;
}
default:
throw new Error(`failed request. unsupported currency ${currency}`);
}
return convertedAmount;
}

/**
* @beta
* PaymentRailsInfo represents payment info for payment rails
Expand All @@ -149,10 +181,10 @@ export type PaymentRailsInfo = {
*/
export type PaymentRailsChainInfo = {
nonce: bigint;
amount: bigint;
amount: string;
currency: SupportedCurrencies | string;
chainId: string;
expirationDate?: string;
expirationDate?: Date;
features?: PaymentFeatures[];
type:
| PaymentRequestDataType.Iden3PaymentRailsRequestV1
Expand Down Expand Up @@ -514,27 +546,28 @@ export class PaymentHandler
if (type === PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1 && !tokenAddress) {
throw new Error(`failed request. no token address for currency ${currency}`);
}
const expirationTime = expirationDate
? new Date(expirationDate).getTime()
: new Date(new Date().setHours(new Date().getHours() + 1)).getTime();
const expirationDateRequired =
expirationDate ?? new Date(new Date().setHours(new Date().getHours() + 1));
const typeUrl = `https://schema.iden3.io/core/json/${type}.json`;
const typesFetchResult = await fetch(typeUrl);
const types = await typesFetchResult.json();
delete types.EIP712Domain;

const convertedAmount = await convertPaymentAmount(amount, currency as SupportedCurrencies);
const paymentData =
type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
? {
recipient,
amount,
expirationDate: expirationTime,
amount: convertedAmount,
expirationDate: getUnixTimestamp(expirationDateRequired),
nonce,
metadata: '0x'
}
: {
tokenAddress,
recipient,
amount,
expirationDate: expirationTime,
amount: convertedAmount,
expirationDate: getUnixTimestamp(expirationDateRequired),
nonce,
metadata: '0x'
};
Expand Down Expand Up @@ -570,7 +603,7 @@ export class PaymentHandler
recipient,
amount: amount.toString(),
currency,
expirationDate: new Date(expirationTime).toISOString(),
expirationDate: getUnixTimestamp(expirationDateRequired).toString(),
nonce: nonce.toString(),
metadata: '0x',
proof
Expand Down
1 change: 1 addition & 0 deletions src/storage/blockchain/abi/ERC20.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"internalType":"uint256","name":"initialSupply","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Contract, Signer } from 'ethers';
import { Contract, Signer, ethers } from 'ethers';

import abi from './abi/ERC20Permit.json';
import permitAbi from './abi/ERC20Permit.json';
import erc20Abi from './abi/ERC20.json';

/**
* @beta
Expand All @@ -19,7 +20,7 @@ export async function getPermitSignature(
value: bigint,
deadline: number
) {
const erc20PermitContract = new Contract(tokenAddress, abi, signer);
const erc20PermitContract = new Contract(tokenAddress, permitAbi, signer);
const nonce = await erc20PermitContract.nonces(await signer.getAddress());
const domainData = await erc20PermitContract.eip712Domain();
const domain = {
Expand Down Expand Up @@ -49,3 +50,16 @@ export async function getPermitSignature(

return signer.signTypedData(domain, types, message);
}

/**
* @beta
* getERC20Decimals is a function to retrieve the number of decimals of an ERC20 token
* @param {string} tokenAddress - Token address
*/
export async function getERC20Decimals(
tokenAddress: string,
runner: ethers.ContractRunner
): Promise<number> {
const erc20Contract = new Contract(tokenAddress, erc20Abi, runner);
return erc20Contract.decimals();
}
2 changes: 1 addition & 1 deletion src/storage/blockchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ export * from './state';
export * from './onchain-zkp-verifier';
export * from './onchain-revocation';
export * from './did-resolver-readonly-storage';
export * from './erc20-permit-sig';
export * from './erc20-helper';
1 change: 1 addition & 0 deletions src/verifiable/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export enum SupportedCurrencies {
ETH_WEI = 'ETHWEI',
ETH_GWEI = 'ETHGWEI',
MATIC = 'MATIC',
POL = 'POL',
USDT = 'USDT',
USDC = 'USDC'
}
Expand Down
Loading

0 comments on commit 6ee11ed

Please sign in to comment.