From 5e6e9050aa0e09f699f9d9fc96595bdaad7f4552 Mon Sep 17 00:00:00 2001 From: Ashis Kumar Pradhan <38760485+akp111@users.noreply.github.com> Date: Fri, 29 Sep 2023 20:54:41 +0530 Subject: [PATCH] Add counter for update channel (#740) * fix: added counter to update group * fix: added counter logic, moved delegate and alias function to channel class --- .../src/lib/pushNotification/channel.ts | 21 ++++-- .../pushNotification/pushNotificationBase.ts | 24 ++++++- packages/restapi/src/lib/pushapi/PushAPI.ts | 7 +- .../tests/lib/pushNotification/alias.test.ts | 2 +- .../lib/pushNotification/delegate.test.ts | 32 ++++----- .../lib/pushNotification/notification.test.ts | 2 +- .../lib/pushNotification/onchain.test.ts | 66 ++++++++++++------- 7 files changed, 100 insertions(+), 54 deletions(-) diff --git a/packages/restapi/src/lib/pushNotification/channel.ts b/packages/restapi/src/lib/pushNotification/channel.ts index b21fa4e3a..da57c04bb 100644 --- a/packages/restapi/src/lib/pushNotification/channel.ts +++ b/packages/restapi/src/lib/pushNotification/channel.ts @@ -23,10 +23,16 @@ import PROGRESSHOOK from '../progressHook'; import { ethers } from 'ethers'; import { PushNotificationBaseClass } from './pushNotificationBase'; +import { Delegate } from './delegate'; +import { Alias } from './alias'; export class Channel extends PushNotificationBaseClass { + public delegate!: Delegate + public alias!: Alias constructor(signer?: SignerType, env?: ENV, account?: string) { super(signer, env, account); + this.delegate = new Delegate(signer, env, account) + this.alias = new Alias(env!); } /** @@ -250,11 +256,14 @@ export class Channel extends PushNotificationBaseClass { config.TOKEN_VIEM_NETWORK_MAP[this.env!] ); const balance = await this.fetchBalance(pushTokenContract, this.account!); + // get counter + const counter = await this.fetchUpdateCounter(this.coreContract, this.account!); const fees = ethers.utils.parseUnits( config.MIN_TOKEN_BALANCE[this.env!].toString(), 18 ); - if (fees.gt(balance)) { + const totalFees = fees.mul(counter) + if (totalFees.gte(balance)) { throw new Error('Insufficient PUSH balance'); } // if alias is passed, check for the caip @@ -285,12 +294,12 @@ export class Channel extends PushNotificationBaseClass { config.CORE_CONFIG[this.env!].EPNS_CORE_CONTRACT ); // if allowance is not greater than the fees, dont call approval again - if (!allowanceAmount.gte(fees)) { + if (!allowanceAmount.gte(totalFees)) { progressHook?.(PROGRESSHOOK['PUSH-UPDATE-02'] as ProgressHookType); const approvalRes = await this.approveToken( pushTokenContract, config.CORE_CONFIG[this.env!].EPNS_CORE_CONTRACT, - fees + totalFees ); if (!approvalRes) { throw new Error('Something went wrong while approving the token'); @@ -305,7 +314,7 @@ export class Channel extends PushNotificationBaseClass { this.coreContract, this.account!, identityBytes, - fees + totalFees ); progressHook?.(PROGRESSHOOK['PUSH-UPDATE-04'] as ProgressHookType); return { transactionHash: updateChannelRes }; @@ -343,6 +352,10 @@ export class Channel extends PushNotificationBaseClass { if (!ethers.utils.isAddress(channelToBeVerified)) { throw new Error('Invalid channel address'); } + const channelDetails = await this.info(this.account); + if(channelDetails?.verified_status == 0){ + throw new Error("Only verified channel can verify other channel") + } // if valid, continue with it const res = await this.verifyChannel( this.coreContract, diff --git a/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts b/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts index c081b2f0e..1d9aab9ab 100644 --- a/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts +++ b/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts @@ -328,6 +328,26 @@ export class PushNotificationBaseClass { } } + protected async fetchUpdateCounter(contract: any, userAddress: string) { + let count: BigNumber; + try { + if ('_signTypedData' in this.signer!) { + count = await contract!['channelUpdateCounter'](userAddress); + } else if ('signTypedData' in this.signer!) { + const countInBigInt = await contract.read.channelUpdateCounter({ + args: [userAddress], + }); + count = ethers.BigNumber.from(countInBigInt); + } else { + throw new Error('Unsupported signer'); + } + // add one and return the count + return count.add(ethers.BigNumber.from(1)); + } catch (error) { + throw new Error(JSON.stringify(error)); + } + } + protected async approveToken( contract: any, spenderAddress: string, @@ -650,7 +670,9 @@ export class PushNotificationBaseClass { ele.data.upper; notificationSettingDescription = - notificationSettingDescription + SETTING_SEPARATOR + ele.description; + notificationSettingDescription + + SETTING_SEPARATOR + + ele.description; } } } diff --git a/packages/restapi/src/lib/pushapi/PushAPI.ts b/packages/restapi/src/lib/pushapi/PushAPI.ts index 2e959a20d..5606e391d 100644 --- a/packages/restapi/src/lib/pushapi/PushAPI.ts +++ b/packages/restapi/src/lib/pushapi/PushAPI.ts @@ -10,9 +10,8 @@ import { Encryption } from './encryption'; import { User } from './user'; import { PushStream } from '../pushstream/PushStream'; import { Channel } from '../pushNotification/channel'; -import { Alias } from '../pushNotification/alias'; -import { Delegate } from '../pushNotification/delegate'; import { Notification } from '../pushNotification/notification'; + export class PushAPI { private signer: SignerType; private account: string; @@ -28,8 +27,6 @@ export class PushAPI { public stream!: PushStream; // Notification public channel!: Channel; - public alias!: Alias; - public delegate!: Delegate; public notification!: Notification; private constructor( @@ -48,8 +45,6 @@ export class PushAPI { this.progressHook = progressHook; // Instantiate the notification classes this.channel = new Channel(this.signer, this.env, this.account); - this.alias = new Alias(this.env); - this.delegate = new Delegate(this.signer, this.env, this.account); this.notification = new Notification(this.signer, this.env, this.account); // Initialize the instances of the four classes this.chat = new Chat( diff --git a/packages/restapi/tests/lib/pushNotification/alias.test.ts b/packages/restapi/tests/lib/pushNotification/alias.test.ts index 1bd9c5cfb..ae62cf864 100644 --- a/packages/restapi/tests/lib/pushNotification/alias.test.ts +++ b/packages/restapi/tests/lib/pushNotification/alias.test.ts @@ -42,7 +42,7 @@ describe('PushAPI.alias functionality', () => { describe('alias :: info', () => { // TODO: remove skip after signer becomes optional it('Should return response', async () => { - const res = await userBob.alias.info({ + const res = await userBob.channel.alias.info({ alias: '0x93A829d16DE51745Db0530A0F8E8A9B8CA5370E5', aliasChain: 'POLYGON', }); diff --git a/packages/restapi/tests/lib/pushNotification/delegate.test.ts b/packages/restapi/tests/lib/pushNotification/delegate.test.ts index 9f99794df..71a723cd2 100644 --- a/packages/restapi/tests/lib/pushNotification/delegate.test.ts +++ b/packages/restapi/tests/lib/pushNotification/delegate.test.ts @@ -41,7 +41,7 @@ describe('PushAPI.delegate functionality', () => { // TODO: remove skip after signer becomes optional it.skip('Without signer and account :: should throw error', async () => { await expect(() => - userBob.delegate.add( + userBob.channel.delegate.add( 'eip155:5:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ) ).to.Throw; @@ -49,14 +49,14 @@ describe('PushAPI.delegate functionality', () => { it('With signer and without provider :: should throw error', async () => { await expect(() => - userAlice.delegate.add( + userAlice.channel.delegate.add( 'eip155:5:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ) ).to.Throw; }); it('With signer and provider :: should add delegate', async () => { - const res = await userKate.delegate.add( + const res = await userKate.channel.delegate.add( 'eip155:5:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ); // console.log(res); @@ -65,7 +65,7 @@ describe('PushAPI.delegate functionality', () => { it('With signer and provider :: should throw error as delegate caip and provider doesnt match', async () => { await expect(() => - userKate.delegate.add( + userKate.channel.delegate.add( 'eip155:80001:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ) ).to.Throw; @@ -82,7 +82,7 @@ describe('PushAPI.delegate functionality', () => { provider ); userKate = await PushAPI.initialize(signer2); - const res = await userKate.delegate.add( + const res = await userKate.channel.delegate.add( 'eip155:80001:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ); // console.log(res); @@ -94,7 +94,7 @@ describe('PushAPI.delegate functionality', () => { // TODO: remove skip after signer becomes optional it.skip('Without signer and account :: should throw error', async () => { await expect(() => - userBob.delegate.remove( + userBob.channel.delegate.remove( 'eip155:5:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ) ).to.Throw; @@ -102,14 +102,14 @@ describe('PushAPI.delegate functionality', () => { it('With signer and without provider :: should throw error', async () => { await expect(() => - userAlice.delegate.remove( + userAlice.channel.delegate.remove( 'eip155:5:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ) ).to.Throw; }); it('With signer and provider :: should add delegate', async () => { - const res = await userKate.delegate.remove( + const res = await userKate.channel.delegate.remove( 'eip155:5:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ); console.log(res); @@ -118,13 +118,13 @@ describe('PushAPI.delegate functionality', () => { it('With signer and provider :: should throw error as delegate caip and provider doesnt match', async () => { await expect(() => - userKate.delegate.remove( + userKate.channel.delegate.remove( 'eip155:80001:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ) ).to.Throw; }); - it('With viem signer: Should add delegate', async () => { + it.only('With viem signer: Should remove delegate', async () => { // create polygon mumbai provider const provider = new ethers.providers.JsonRpcProvider( 'https://rpc-mumbai.maticvigil.com' @@ -135,7 +135,7 @@ describe('PushAPI.delegate functionality', () => { provider ); userKate = await PushAPI.initialize(signer2); - const res = await userKate.delegate.remove( + const res = await userKate.channel.delegate.remove( 'eip155:80001:0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924' ); // console.log(res); @@ -145,18 +145,18 @@ describe('PushAPI.delegate functionality', () => { describe('delegate :: get', () => { it.skip('Without signer and account : Should throw error', async () => { - await expect(() => userBob.delegate.get()).to.Throw; + await expect(() => userBob.channel.delegate.get()).to.Throw; }); it('Without signer : Should throw error for non-caip format', async () => { await expect(() => - userBob.delegate.get({ + userBob.channel.delegate.get({ channel: '0x74415Bc4C4Bf4Baecc2DD372426F0a1D016Fa924', }) ).to.Throw; }); it('Without signer : Should fetch delegates', async () => { - const res = await userBob.delegate.get({ + const res = await userBob.channel.delegate.get({ channel: 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681', }); console.log(res); @@ -164,7 +164,7 @@ describe('PushAPI.delegate functionality', () => { }); it('Without signer : Should fetch delegates for alias', async () => { - const res = await userBob.delegate.get({ + const res = await userBob.channel.delegate.get({ channel: 'eip155:80001:0xD8634C39BBFd4033c0d3289C4515275102423681', }); // console.log(res) @@ -172,7 +172,7 @@ describe('PushAPI.delegate functionality', () => { }); it('With signer : Should fetch delegates for channel', async () => { - const res = await userKate.delegate.get(); + const res = await userKate.channel.delegate.get(); // console.log(res); expect(res).not.null; }); diff --git a/packages/restapi/tests/lib/pushNotification/notification.test.ts b/packages/restapi/tests/lib/pushNotification/notification.test.ts index d9a6ec2c3..31442a287 100644 --- a/packages/restapi/tests/lib/pushNotification/notification.test.ts +++ b/packages/restapi/tests/lib/pushNotification/notification.test.ts @@ -52,7 +52,7 @@ describe('PushAPI.notification functionality', () => { userViem = await PushAPI.initialize(viemSigner); }); - describe('', () => { + describe('PushAPI.notification functionality', () => { it('Should return feeds with signer object', async () => { const response = await userAlice.notification.list('SPAM'); expect(response).not.null; diff --git a/packages/restapi/tests/lib/pushNotification/onchain.test.ts b/packages/restapi/tests/lib/pushNotification/onchain.test.ts index e5412da59..c8e91058c 100644 --- a/packages/restapi/tests/lib/pushNotification/onchain.test.ts +++ b/packages/restapi/tests/lib/pushNotification/onchain.test.ts @@ -3,8 +3,8 @@ // dotenv.config({ path: path.resolve(__dirname, '../../../.env') }); // import { expect } from 'chai'; // import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; - -// import { PushNotification } from '../../../../src/lib/pushNotification/PushNotification'; +// import { PushNotificationBaseClass } from '../../../src/lib/pushNotification/pushNotificationBase'; +// import * as config from "../../../src/lib/config" // import { // createWalletClient, // http, @@ -15,6 +15,15 @@ // import { goerli, polygonMumbai } from 'viem/chains'; // import { BigNumber, ethers } from 'ethers'; +// enum ENV { +// PROD = 'prod', +// STAGING = 'staging', +// DEV = 'dev', +// /** +// * **This is for local development only** +// */ +// LOCAL = 'local', +// } // describe.only('test', () => { // const signer = createWalletClient({ // account: privateKeyToAccount(`0x${process.env['WALLET_PRIVATE_KEY']}`), @@ -37,32 +46,35 @@ // `0x${process.env['WALLET_PRIVATE_KEY']}`, // provider // ); - -// it.only('testing with viem', async () => { -// const userViem = await PushNotification.initialize(signer); +// it('testing with viem', async () => { +// const account2 = await signer2.getAddress(); +// const viemUser = new PushNotificationBaseClass(signer, ENV.STAGING, account2) +// const contract = viemUser.createContractInstance("0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C", config.ABIS.CORE, goerli) +// const res = await viemUser.fetchUpdateCounter(contract, account2); +// console.log(res) // const viemContract = await userViem.createContractInstance( // '0x2b9bE9259a4F5Ba6344c1b1c07911539642a2D33', // abi, // goerli // ); -// // const balance = await userViem.fetchBalance( -// // viemContract, -// // '0xD8634C39BBFd4033c0d3289C4515275102423681' -// // ); -// // console.log(balance); -// // const allowance = await userViem.fetchAllownace( -// // viemContract, -// // '0xD8634C39BBFd4033c0d3289C4515275102423681', -// // '0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C' -// // ); -// // console.log(allowance); -// // const approveAmount = ethers.BigNumber.from(10000); -// // const approveRes = await userViem.approveToken( -// // viemContract, -// // '0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C', -// // approveAmount -// // ); -// // console.log(approveRes); +// const balance = await userViem.fetchBalance( +// viemContract, +// '0xD8634C39BBFd4033c0d3289C4515275102423681' +// ); +// console.log(balance); +// const allowance = await userViem.fetchAllownace( +// viemContract, +// '0xD8634C39BBFd4033c0d3289C4515275102423681', +// '0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C' +// ); +// console.log(allowance); +// const approveAmount = ethers.BigNumber.from(10000); +// const approveRes = await userViem.approveToken( +// viemContract, +// '0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C', +// approveAmount +// ); +// console.log(approveRes); // const addDelegate = await userViem.delegate.add( // 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681' @@ -70,8 +82,12 @@ // console.log(addDelegate); // }); -// it('test with ethers', async () => { -// const userEthers = await PushNotification.initialize(signer2); +// it.only('test with ethers', async () => { +// const account2 = await signer2.getAddress(); +// const userEthers = new PushNotificationBaseClass(signer2, ENV.STAGING, account2,); +// const contract = userEthers.createContractInstance("0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C", config.ABIS.CORE, goerli) +// const res = await userEthers.fetchUpdateCounter(contract, account2); +// console.log(res) // const ethersContract = await userEthers.createContractInstance( // '0x2b9bE9259a4F5Ba6344c1b1c07911539642a2D33', // abi,