From 0c8f92b72998c59d6503216cb7fefe5d094a4ac3 Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 19 Mar 2024 01:33:19 +0530 Subject: [PATCH 1/3] added arka wrapper as sub package --- examples/24-ArkaPaymaster.ts | 23 ++++ src/sdk/index.ts | 3 +- src/sdk/interfaces.ts | 1 - src/sdk/paymaster/ErrorMsg.ts | 5 + src/sdk/paymaster/index.ts | 2 + src/sdk/paymaster/interface.ts | 6 + src/sdk/paymaster/provider/arka.ts | 194 ++++++++++++++++++++++++++++ src/sdk/paymaster/provider/index.ts | 1 + 8 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 examples/24-ArkaPaymaster.ts create mode 100644 src/sdk/paymaster/ErrorMsg.ts create mode 100644 src/sdk/paymaster/index.ts create mode 100644 src/sdk/paymaster/interface.ts create mode 100644 src/sdk/paymaster/provider/arka.ts create mode 100644 src/sdk/paymaster/provider/index.ts diff --git a/examples/24-ArkaPaymaster.ts b/examples/24-ArkaPaymaster.ts new file mode 100644 index 0000000..0a3e8ed --- /dev/null +++ b/examples/24-ArkaPaymaster.ts @@ -0,0 +1,23 @@ +import { ArkaPaymaster } from "../src"; +import * as dotenv from 'dotenv'; + +dotenv.config(); + +async function main() { + const arka_api_key = 'arka_public_key'; + const arka_url = 'https://arka.etherspot.io'; // Only testnets are available, if you need further assistance in setting up a paymaster service for your dapp, please reach out to us on discord or https://etherspot.fyi/arka/intro + + // initializating sdk... + const arkaPaymaster = new ArkaPaymaster(Number(process.env.CHAIN_ID), arka_api_key, arka_url); + + console.log(await arkaPaymaster.metadata()); + console.log(await arkaPaymaster.getTokenPaymasterAddress("eUSDC")) + console.log(await arkaPaymaster.addWhitelist(["0xB3aF6CFDDc444B948132753AD8214a20605692eF"])); + console.log(await arkaPaymaster.removeWhitelist(["0xB3aF6CFDDc444B948132753AD8214a20605692eF"])); + console.log(await arkaPaymaster.checkWhitelist("0xB3aF6CFDDc444B948132753AD8214a20605692eF")); + console.log(await arkaPaymaster.deposit(0.001)); +} + +main() + .catch(console.error) + .finally(() => process.exit()); \ No newline at end of file diff --git a/src/sdk/index.ts b/src/sdk/index.ts index 285e588..6e3085d 100644 --- a/src/sdk/index.ts +++ b/src/sdk/index.ts @@ -1,5 +1,6 @@ import { DataUtils } from './dataUtils'; import { PrimeSdk } from './sdk'; +import { ArkaPaymaster } from './paymaster'; export * from './api'; export * from './dto'; @@ -9,5 +10,5 @@ export * from './state'; export * from './wallet'; export * from './bundler'; -export { PrimeSdk, DataUtils }; +export { PrimeSdk, DataUtils, ArkaPaymaster }; export default PrimeSdk; \ No newline at end of file diff --git a/src/sdk/interfaces.ts b/src/sdk/interfaces.ts index 4ef7301..9b5c28a 100644 --- a/src/sdk/interfaces.ts +++ b/src/sdk/interfaces.ts @@ -19,7 +19,6 @@ export interface SdkOptions { stateStorage?: StateStorage; rpcProviderUrl?: string; graphqlEndpoint?: string; - etherspotBundlerApiKey?: string; factoryWallet?: Factory; walletFactoryAddress?: string; entryPointAddress?: string; diff --git a/src/sdk/paymaster/ErrorMsg.ts b/src/sdk/paymaster/ErrorMsg.ts new file mode 100644 index 0000000..d8100e5 --- /dev/null +++ b/src/sdk/paymaster/ErrorMsg.ts @@ -0,0 +1,5 @@ +export const ErrorMessage = { + INVALID_ADDRESSES: 'Address Invalid. Please make sure that all the addresses are valid', + INVALID_ADDRESS: 'The given address is invalid. Please try again with valid address', + MAX_ADDRESSES: 'Max of 10 addresses are only allowed in one request', +} \ No newline at end of file diff --git a/src/sdk/paymaster/index.ts b/src/sdk/paymaster/index.ts new file mode 100644 index 0000000..e7adc5a --- /dev/null +++ b/src/sdk/paymaster/index.ts @@ -0,0 +1,2 @@ +export * from './interface'; +export * from './providers'; \ No newline at end of file diff --git a/src/sdk/paymaster/interface.ts b/src/sdk/paymaster/interface.ts new file mode 100644 index 0000000..8cbc525 --- /dev/null +++ b/src/sdk/paymaster/interface.ts @@ -0,0 +1,6 @@ + +export interface PaymasterProvider { + readonly url: string; +} + +export type PaymasterProviderLike = PaymasterProvider; \ No newline at end of file diff --git a/src/sdk/paymaster/provider/arka.ts b/src/sdk/paymaster/provider/arka.ts new file mode 100644 index 0000000..82cb268 --- /dev/null +++ b/src/sdk/paymaster/provider/arka.ts @@ -0,0 +1,194 @@ +import { ethers } from "ethers"; +import { PaymasterProvider } from "../interface"; +import { ErrorMessage } from "../ErrorMsg"; + +export class ArkaPaymaster implements PaymasterProvider { + readonly url: string; + readonly apiKey: string; + readonly chainId: number; + readonly queryParams: string; + + constructor(chainId: number, apiKey: string, paymasterUrl: string) { + this.url = paymasterUrl; + this.queryParams = `?apiKey=${apiKey}&chainId=${chainId}`; + this.apiKey = apiKey; + this.chainId = chainId; + } + + async getTokenPaymasterAddress(tokenSym: string) { + let response = null; + const entryPointAddress = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'; + const context = { token: tokenSym } + try { + response = await fetch(`${this.url}/pimlicoAddress${this.queryParams}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ params: [entryPointAddress, context] }), + }) + .then(async (res) => { + const responseJson = await res.json(); + if (responseJson.error) { + throw new Error(responseJson.error); + } + return responseJson + }) + .catch((err) => { + throw new Error(err.message); + }) + } catch (err) { + throw new Error(err.message) + } + if (response.message) return response.message; + return response; + } + + async addWhitelist(addresses: string[]) { + let response = null; + if (addresses.length > 10) throw new Error(ErrorMessage.MAX_ADDRESSES); + const validAddresses = addresses.every(ethers.utils.isAddress); + if (!validAddresses) throw new Error(ErrorMessage.INVALID_ADDRESS); + try { + response = await fetch(`${this.url}/whitelist${this.queryParams}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ params: [addresses] }), + }) + .then(async (res) => { + const responseJson = await res.json(); + if (responseJson.error) { + throw new Error(responseJson.error); + } + return responseJson + }) + .catch((err) => { + throw new Error(err.message); + }) + } catch (err) { + throw new Error(err.message) + } + if (response.message) return response.message; + return response; + } + + async removeWhitelist(addresses: string[]) { + let response = null; + if (addresses.length > 10) throw new Error(ErrorMessage.MAX_ADDRESSES); + const validAddresses = addresses.every(ethers.utils.isAddress); + if (!validAddresses) throw new Error(ErrorMessage.INVALID_ADDRESS); + try { + response = await fetch(`${this.url}/removeWhitelist${this.queryParams}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ params: [addresses] }), + }) + .then(async (res) => { + const responseJson = await res.json(); + if (responseJson.error) { + throw new Error(responseJson.error); + } + return responseJson + }) + .catch((err) => { + throw new Error(err.message); + }) + } catch (err) { + throw new Error(err.message) + } + if (response.message) return response.message; + return response; + } + + async checkWhitelist(address: string) { + let response = null; + if (!ethers.utils.isAddress(address)) throw new Error(ErrorMessage.INVALID_ADDRESS) + try { + response = await fetch(`${this.url}/checkWhitelist${this.queryParams}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ params: [address] }), + }) + .then(async (res) => { + const responseJson = await res.json(); + if (responseJson.error) { + throw new Error(responseJson.error); + } + return responseJson + }) + .catch((err) => { + throw new Error(err.message); + }) + } catch (err) { + throw new Error(err.message) + } + if (response.message) return response.message; + return response; + } + + async deposit(amountInEth: number) { + let response = null; + try { + response = await fetch(`${this.url}/deposit${this.queryParams}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ params: [amountInEth] }), + }) + .then(async (res) => { + const responseJson = await res.json(); + if (responseJson.error) { + throw new Error(responseJson.error); + } + return responseJson + }) + .catch((err) => { + throw new Error(err.message); + }) + } catch (err) { + throw new Error(err.message) + } + if (response.message) return response.message; + return response; + } + + async metadata() { + let response = null; + try { + response = await fetch(`${this.url}/metadata${this.queryParams}`, { + method: 'GET', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + }) + .then(async (res) => { + const responseJson = await res.json(); + if (responseJson.error) { + throw new Error(responseJson.error); + } + return responseJson + }) + .catch((err) => { + throw new Error(err.message); + }) + } catch (err) { + throw new Error(err.message) + } + if (response.message) return response.message; + return response; + } + +} \ No newline at end of file diff --git a/src/sdk/paymaster/provider/index.ts b/src/sdk/paymaster/provider/index.ts new file mode 100644 index 0000000..adcfea1 --- /dev/null +++ b/src/sdk/paymaster/provider/index.ts @@ -0,0 +1 @@ +export * from './arka'; \ No newline at end of file From fa43511b1d9a8b99243cd2bf24ebe780e490b1a7 Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 19 Mar 2024 01:36:21 +0530 Subject: [PATCH 2/3] updated package version --- CHANGELOG.md | 4 ++++ package-lock.json | 4 ++-- package.json | 2 +- src/sdk/paymaster/index.ts | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f1e7c..1a3eb51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +## [1.6.3] - 2024-03-19 +### New +- Added ArkaPaymaster as a sub-module + ## [1.6.2] - 2024-03-15 ### Bug Fixes - Fixed browser-side querystring issue diff --git a/package-lock.json b/package-lock.json index ab16e9a..18b84c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@etherspot/prime-sdk", - "version": "1.6.2", + "version": "1.6.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@etherspot/prime-sdk", - "version": "1.6.2", + "version": "1.6.3", "license": "MIT", "dependencies": { "@apollo/client": "3.8.7", diff --git a/package.json b/package.json index 6df295f..605581e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@etherspot/prime-sdk", - "version": "1.6.2", + "version": "1.6.3", "description": "Etherspot Prime (Account Abstraction) SDK", "keywords": [ "ether", diff --git a/src/sdk/paymaster/index.ts b/src/sdk/paymaster/index.ts index e7adc5a..df035a0 100644 --- a/src/sdk/paymaster/index.ts +++ b/src/sdk/paymaster/index.ts @@ -1,2 +1,2 @@ export * from './interface'; -export * from './providers'; \ No newline at end of file +export * from './provider'; \ No newline at end of file From 8e50a6e954b0c55cebf0fbdb33b2bb0d78c59ca8 Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 19 Mar 2024 16:16:39 +0530 Subject: [PATCH 3/3] changes as per feedback --- src/sdk/paymaster/provider/arka.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/sdk/paymaster/provider/arka.ts b/src/sdk/paymaster/provider/arka.ts index 82cb268..c7b7fc8 100644 --- a/src/sdk/paymaster/provider/arka.ts +++ b/src/sdk/paymaster/provider/arka.ts @@ -15,9 +15,12 @@ export class ArkaPaymaster implements PaymasterProvider { this.chainId = chainId; } + /* This method is to get the paymaster address for the given token symbol if available + * @param tokenSym, the token symbol used as string ex: "USDC" + */ async getTokenPaymasterAddress(tokenSym: string) { let response = null; - const entryPointAddress = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'; + const entryPointAddressV06 = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'; const context = { token: tokenSym } try { response = await fetch(`${this.url}/pimlicoAddress${this.queryParams}`, { @@ -26,7 +29,7 @@ export class ArkaPaymaster implements PaymasterProvider { 'Accept': 'application/json', 'Content-Type': 'application/json', }, - body: JSON.stringify({ params: [entryPointAddress, context] }), + body: JSON.stringify({ params: [entryPointAddressV06, context] }), }) .then(async (res) => { const responseJson = await res.json(); @@ -45,6 +48,9 @@ export class ArkaPaymaster implements PaymasterProvider { return response; } + /* This method is to whitelist the addresses given + * @param addresses, the array of addresses that needs to be whitelisted + */ async addWhitelist(addresses: string[]) { let response = null; if (addresses.length > 10) throw new Error(ErrorMessage.MAX_ADDRESSES); @@ -76,6 +82,9 @@ export class ArkaPaymaster implements PaymasterProvider { return response; } + /* This method is to remove whitelisted addresses given + * @param addresses, the array of addresses that needs to be removed from whitelist + */ async removeWhitelist(addresses: string[]) { let response = null; if (addresses.length > 10) throw new Error(ErrorMessage.MAX_ADDRESSES); @@ -107,6 +116,9 @@ export class ArkaPaymaster implements PaymasterProvider { return response; } + /* This method is to check a given address is whitelisted or not + * @param address, address that needs to be checked if its whitelisted or not + */ async checkWhitelist(address: string) { let response = null; if (!ethers.utils.isAddress(address)) throw new Error(ErrorMessage.INVALID_ADDRESS) @@ -136,6 +148,9 @@ export class ArkaPaymaster implements PaymasterProvider { return response; } + /* This method is to deposit the amount for the paymaster to the entryPoint contract + * @param amountInEth, amount that needs to be deposited in ETH terms + */ async deposit(amountInEth: number) { let response = null; try { @@ -164,6 +179,7 @@ export class ArkaPaymaster implements PaymasterProvider { return response; } + // This method is to get the details of the paymaster associated to your apiKey async metadata() { let response = null; try {