diff --git a/.changeset/crazy-clouds-press.md b/.changeset/crazy-clouds-press.md new file mode 100644 index 000000000..f4a575a2a --- /dev/null +++ b/.changeset/crazy-clouds-press.md @@ -0,0 +1,5 @@ +--- +'@lit-protocol/networks': major +--- + +add missing `withdraw` ledge abi method diff --git a/.changeset/pre.json b/.changeset/pre.json index ee9e9eb24..ba93e7475 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -26,6 +26,7 @@ "brown-houses-matter", "chatty-poets-grow", "chilly-rice-stand", + "crazy-clouds-press", "cuddly-comics-take", "cuddly-rats-say", "curvy-trams-fly", @@ -48,7 +49,9 @@ "puny-lines-know", "purple-ants-shake", "quick-parts-enjoy", + "quick-tigers-fix", "quiet-bees-exist", + "real-plants-fail", "rude-chicken-join", "short-signs-check", "silent-crabs-take", diff --git a/.changeset/quick-tigers-fix.md b/.changeset/quick-tigers-fix.md new file mode 100644 index 000000000..032ad9d12 --- /dev/null +++ b/.changeset/quick-tigers-fix.md @@ -0,0 +1,5 @@ +--- +'@lit-protocol/networks': major +--- + +add payment delegation manager diff --git a/.changeset/real-plants-fail.md b/.changeset/real-plants-fail.md new file mode 100644 index 000000000..830518ef5 --- /dev/null +++ b/.changeset/real-plants-fail.md @@ -0,0 +1,5 @@ +--- +'@lit-protocol/networks': major +--- + +add payment delegation apis diff --git a/bun.lock b/bun.lock index 14b773714..0acc23c8f 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,7 @@ "name": "@lit-protocol/js-sdk", "dependencies": { "@dotenvx/dotenvx": "^1.6.4", - "@lit-protocol/contracts": "^0.1.34", + "@lit-protocol/contracts": "^0.2.0", "@lit-protocol/nacl": "7.1.1", "@lit-protocol/uint8arrays": "7.1.1", "@metamask/eth-sig-util": "5.0.2", @@ -220,9 +220,9 @@ }, "packages/networks": { "name": "@lit-protocol/networks", - "version": "8.0.0-alpha.22", + "version": "8.0.0-alpha.23", "dependencies": { - "@lit-protocol/contracts": "^0.1.34", + "@lit-protocol/contracts": "^0.2.0", "@lit-protocol/nacl": "7.1.1", "@noble/curves": "^1.8.1", "@wagmi/core": "^2.17.1", @@ -1078,7 +1078,7 @@ "@lit-protocol/constants": ["@lit-protocol/constants@workspace:packages/constants"], - "@lit-protocol/contracts": ["@lit-protocol/contracts@0.1.34", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-Cg+3SrHjnGAxNLB85n+QlmkcgCX99I0VQQ1KVrk3nix/IXoMzG4Mm/najb9EDPegi76WKWKrt2nhqhAkmGj9LQ=="], + "@lit-protocol/contracts": ["@lit-protocol/contracts@0.2.0", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-AoSTZbrGwdnPJjC68rN6vnapmzMCKdvqGyi7OM+dCBRI/pgm7e3b3NXdtAOz5ynzAtnL3gcF9RxqoQthcbBIKw=="], "@lit-protocol/crypto": ["@lit-protocol/crypto@workspace:packages/crypto"], diff --git a/e2e/src/e2e.spec.ts b/e2e/src/e2e.spec.ts index d3142eb38..9d5f11602 100644 --- a/e2e/src/e2e.spec.ts +++ b/e2e/src/e2e.spec.ts @@ -15,6 +15,7 @@ import { createViewPKPsByAddressTest, createViewPKPsByAuthDataTest, createPaymentManagerFlowTest, + createPaymentDelegationFlowTest, } from './helper/tests'; import { init } from './init'; @@ -62,6 +63,8 @@ describe('all', () => { )()); it('paymentManagerFlow', () => createPaymentManagerFlowTest(ctx, () => ctx.aliceEoaAuthContext)()); + it('paymentDelegationFlow', () => + createPaymentDelegationFlowTest(ctx, () => ctx.aliceEoaAuthContext)()); }); describe('integrations', () => { diff --git a/e2e/src/helper/tests/index.ts b/e2e/src/helper/tests/index.ts index e23a45d9a..19467b7ab 100644 --- a/e2e/src/helper/tests/index.ts +++ b/e2e/src/helper/tests/index.ts @@ -7,6 +7,7 @@ export { createPkpEncryptDecryptTest } from './pkp-encrypt-decrypt'; export { createEncryptDecryptFlowTest } from './encrypt-decrypt-flow'; export { createPkpPermissionsManagerFlowTest } from './pkp-permissions-manager-flow'; export { createPaymentManagerFlowTest } from './payment-manager-flow'; +export { createPaymentDelegationFlowTest } from './payment-delegation-flow'; export { createEoaNativeAuthFlowTest } from './eoa-native-auth-flow'; // Viem integration tests diff --git a/e2e/src/helper/tests/payment-delegation-flow.ts b/e2e/src/helper/tests/payment-delegation-flow.ts new file mode 100644 index 000000000..38871bf42 --- /dev/null +++ b/e2e/src/helper/tests/payment-delegation-flow.ts @@ -0,0 +1,142 @@ +import { init } from '../../init'; +import { assert } from '../assertions'; + +export const createPaymentDelegationFlowTest = ( + ctx: Awaited>, + _getAuthContext: () => any +) => { + return async () => { + // Get Payment Manager for Alice (the payer/delegator) + const alicePaymentManager = await ctx.litClient.getPaymentManager({ + account: ctx.aliceViemAccount, + }); + + // Get Payment Manager for Bob (the user/delegatee) + const bobPaymentManager = await ctx.litClient.getPaymentManager({ + account: ctx.bobViemAccount, + }); + + assert.toBeDefined(alicePaymentManager); + assert.toBeDefined(bobPaymentManager); + + const aliceAddress = ctx.aliceViemAccount.address; + const bobAddress = ctx.bobViemAccount.address; + + // Test 1: Get initial payers for Bob + const initialPayers = await bobPaymentManager.getPayers({ + userAddress: bobAddress, + }); + assert.toBe(Array.isArray(initialPayers), true); + const initialPayersCount = initialPayers.length; + console.log('initialPayers', initialPayers); + + // Test 2: Get initial users for Alice + const initialUsers = await alicePaymentManager.getUsers({ + payerAddress: aliceAddress, + }); + assert.toBe(Array.isArray(initialUsers), true); + const initialUsersCount = initialUsers.length; + console.log('initialUsers', initialUsers); + + // Test 3: Alice delegates payment to Bob + const delegateTx = await alicePaymentManager.delegatePayments({ + userAddress: bobAddress, + }); + assert.toBeDefined(delegateTx.hash); + assert.toBeDefined(delegateTx.receipt); + assert.toBe(delegateTx.receipt.status, 'success'); + + // Test 4: Verify Bob now has Alice as a payer + const payersAfterDelegate = await bobPaymentManager.getPayers({ + userAddress: bobAddress, + }); + assert.toBe(payersAfterDelegate.length, initialPayersCount + 1); + assert.toBe(payersAfterDelegate.includes(aliceAddress), true); + console.log('payersAfterDelegate', payersAfterDelegate); + + // Test 5: Verify Alice now has Bob as a user + const usersAfterDelegate = await alicePaymentManager.getUsers({ + payerAddress: aliceAddress, + }); + assert.toBe(usersAfterDelegate.length, initialUsersCount + 1); + assert.toBe(usersAfterDelegate.includes(bobAddress), true); + console.log('usersAfterDelegate', usersAfterDelegate); + + // Test 6: Set a restriction for Alice + const setRestrictionTx = await alicePaymentManager.setRestriction({ + totalMaxPrice: '1000000000000000000', // 1 ETH + requestsPerPeriod: '100', + periodSeconds: '3600', // 1 hour + }); + assert.toBeDefined(setRestrictionTx.hash); + assert.toBe(setRestrictionTx.receipt.status, 'success'); + console.log('setRestrictionTx', setRestrictionTx); + + // Test 7: Get and verify the restriction + const restriction = await alicePaymentManager.getRestriction({ + payerAddress: aliceAddress, + }); + assert.toBeDefined(restriction); + assert.toBe(restriction.totalMaxPrice, '1000000000000000000'); + assert.toBe(restriction.requestsPerPeriod, '100'); + assert.toBe(restriction.periodSeconds, '3600'); + console.log('restriction', restriction); + // Test 8: Test batch operations - create test addresses + const testAddresses = [ + '0x1234567890123456789012345678901234567890', + '0x2345678901234567890123456789012345678901', + ]; + + // Delegate to multiple users + const batchDelegateTx = await alicePaymentManager.delegatePaymentsBatch({ + userAddresses: testAddresses, + }); + assert.toBeDefined(batchDelegateTx.hash); + assert.toBe(batchDelegateTx.receipt.status, 'success'); + console.log('batchDelegateTx', batchDelegateTx); + // Test 9: Verify batch delegation + const usersAfterBatch = await alicePaymentManager.getUsers({ + payerAddress: aliceAddress, + }); + assert.toBe(usersAfterBatch.includes(testAddresses[0]), true); + assert.toBe(usersAfterBatch.includes(testAddresses[1]), true); + console.log('usersAfterBatch', usersAfterBatch); + // Test 10: Get payers and restrictions for multiple users + const payersAndRestrictions = await alicePaymentManager.getPayersAndRestrictions({ + userAddresses: [bobAddress, testAddresses[0]], + }); + assert.toBeDefined(payersAndRestrictions); + assert.toBe(Array.isArray(payersAndRestrictions.payers), true); + assert.toBe(payersAndRestrictions.payers.length, 2); + assert.toBe(Array.isArray(payersAndRestrictions.restrictions), true); + assert.toBe(payersAndRestrictions.restrictions.length, 2); + console.log('payersAndRestrictions', payersAndRestrictions); + // Test 11: Undelegate from batch users + const batchUndelegateTx = await alicePaymentManager.undelegatePaymentsBatch({ + userAddresses: testAddresses, + }); + assert.toBeDefined(batchUndelegateTx.hash); + assert.toBe(batchUndelegateTx.receipt.status, 'success'); + console.log('batchUndelegateTx', batchUndelegateTx); + // Test 12: Alice undelegates payment from Bob + const undelegateTx = await alicePaymentManager.undelegatePayments({ + userAddress: bobAddress, + }); + assert.toBeDefined(undelegateTx.hash); + assert.toBe(undelegateTx.receipt.status, 'success'); + console.log('undelegateTx', undelegateTx); + // Test 13: Verify Bob no longer has Alice as a payer + const finalPayers = await bobPaymentManager.getPayers({ + userAddress: bobAddress, + }); + assert.toBe(finalPayers.length, initialPayersCount); + assert.toBe(finalPayers.includes(aliceAddress), false); + console.log('finalPayers', finalPayers); + // Test 14: Verify Alice no longer has Bob as a user + const finalUsers = await alicePaymentManager.getUsers({ + payerAddress: aliceAddress, + }); + assert.toBe(finalUsers.includes(bobAddress), false); + console.log('finalUsers', finalUsers); + }; +}; \ No newline at end of file diff --git a/e2e/src/init.ts b/e2e/src/init.ts index 271887057..467afe757 100644 --- a/e2e/src/init.ts +++ b/e2e/src/init.ts @@ -30,6 +30,9 @@ export const init = async ( aliceViemAccount: any; aliceViemAccountAuthData: any; aliceViemAccountPkp: any; + bobViemAccount: any; + bobViemAccountAuthData: any; + bobViemAccountPkp: any; aliceEoaAuthContext: any; }> => { /** @@ -47,6 +50,11 @@ export const init = async ( const aliceViemAccountAuthData = await ViemAccountAuthenticator.authenticate( aliceViemAccount ); + + const bobViemAccount = privateKeyToAccount(generatePrivateKey()); + const bobViemAccountAuthData = await ViemAccountAuthenticator.authenticate( + bobViemAccount + ); /** * ==================================== @@ -84,6 +92,10 @@ export const init = async ( ifLessThan: '0.01', thenFundWith: '0.01', }); + await fundAccount(bobViemAccount, liveMasterAccount, _networkModule, { + ifLessThan: '0.01', + thenFundWith: '0.01', + }); } else if (_network === 'naga-test') { const { nagaTest } = await import('@lit-protocol/networks'); _networkModule = nagaTest; @@ -91,6 +103,10 @@ export const init = async ( ifLessThan: '0.01', thenFundWith: '0.01', }); + await fundAccount(bobViemAccount, liveMasterAccount, _networkModule, { + ifLessThan: '0.01', + thenFundWith: '0.01', + }); } else if (_network === 'naga-local') { const { nagaLocal } = await import('@lit-protocol/networks'); _networkModule = nagaLocal; @@ -98,6 +114,10 @@ export const init = async ( ifLessThan: '1', thenFundWith: '1', }); + await fundAccount(bobViemAccount, localMasterAccount, _networkModule, { + ifLessThan: '1', + thenFundWith: '1', + }); } else if (_network === 'naga-staging') { const { nagaStaging } = await import('@lit-protocol/networks'); _networkModule = nagaStaging; @@ -105,6 +125,10 @@ export const init = async ( ifLessThan: '0.0001', thenFundWith: '0.0001', }); + await fundAccount(bobViemAccount, liveMasterAccount, _networkModule, { + ifLessThan: '0.0001', + thenFundWith: '0.0001', + }); } else { throw new Error(`❌ Invalid network: ${_network}`); } @@ -133,7 +157,7 @@ export const init = async ( /** * ==================================== - * Select a PKP + * Select PKPs for Alice and Bob * ==================================== */ const { pkps: aliceViemAccountPkps } = await litClient.viewPKPsByAuthData({ @@ -149,9 +173,22 @@ export const init = async ( }); const aliceViemAccountPkp = aliceViemAccountPkps[0]; + const { pkps: bobViemAccountPkps } = await litClient.viewPKPsByAuthData({ + authData: bobViemAccountAuthData, + pagination: { + limit: 5, + }, + storageProvider: storagePlugins.localStorageNode({ + appName: 'my-app', + networkName: 'naga-dev', + storagePath: './pkp-tokens-bob', + }), + }); + const bobViemAccountPkp = bobViemAccountPkps[0]; + /** * ==================================== - * (Local only) Mint a PKP + * (Local only) Mint PKPs for Alice and Bob * ==================================== */ if (!aliceViemAccountPkp) { @@ -162,9 +199,17 @@ export const init = async ( }); } + if (!bobViemAccountPkp) { + await litClient.mintWithAuth({ + authData: bobViemAccountAuthData, + account: bobViemAccount, + scopes: ['sign-anything'], + }); + } + /** * ==================================== - * Select a PKP + * Select final PKPs for Alice and Bob * ==================================== */ const { pkps: aliceViemAccountPkps2 } = await litClient.viewPKPsByAuthData({ @@ -180,6 +225,19 @@ export const init = async ( }); const aliceViemAccountPkp2 = aliceViemAccountPkps2[0]; + const { pkps: bobViemAccountPkps2 } = await litClient.viewPKPsByAuthData({ + authData: bobViemAccountAuthData, + pagination: { + limit: 5, + }, + storageProvider: storagePlugins.localStorageNode({ + appName: 'my-app', + networkName: 'naga-dev', + storagePath: './pkp-tokens-bob', + }), + }); + const bobViemAccountPkp2 = bobViemAccountPkps2[0]; + /** * ==================================== * Create the auth context @@ -216,6 +274,9 @@ export const init = async ( aliceViemAccount, aliceViemAccountAuthData, aliceViemAccountPkp: aliceViemAccountPkp2, + bobViemAccount, + bobViemAccountAuthData, + bobViemAccountPkp: bobViemAccountPkp2, aliceEoaAuthContext, }; }; diff --git a/package.json b/package.json index 7ec087076..1a8a0087d 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "private": true, "dependencies": { "@dotenvx/dotenvx": "^1.6.4", - "@lit-protocol/contracts": "^0.1.34", + "@lit-protocol/contracts": "^0.2.0", "@lit-protocol/nacl": "7.1.1", "@lit-protocol/uint8arrays": "7.1.1", "@metamask/eth-sig-util": "5.0.2", diff --git a/packages/networks/CHANGELOG.md b/packages/networks/CHANGELOG.md index 864e59576..5bd16896d 100644 --- a/packages/networks/CHANGELOG.md +++ b/packages/networks/CHANGELOG.md @@ -1,5 +1,23 @@ # @lit-protocol/networks +## 8.0.0-alpha.26 + +### Major Changes + +- add missing `withdraw` ledge abi method + +## 8.0.0-alpha.25 + +### Major Changes + +- add payment delegation manager + +## 8.0.0-alpha.24 + +### Major Changes + +- add payment delegation apis + ## 8.0.0-alpha.23 ### Major Changes diff --git a/packages/networks/package.json b/packages/networks/package.json index 61f61a95a..e4b5e9ea3 100644 --- a/packages/networks/package.json +++ b/packages/networks/package.json @@ -18,7 +18,7 @@ "directory": "../../dist/packages/networks" }, "dependencies": { - "@lit-protocol/contracts": "^0.1.34", + "@lit-protocol/contracts": "^0.2.1", "@lit-protocol/nacl": "7.1.1", "@noble/curves": "^1.8.1", "@wagmi/core": "^2.17.1", @@ -35,7 +35,7 @@ "tags": [ "universal" ], - "version": "8.0.0-alpha.23", + "version": "8.0.0-alpha.26", "main": "./dist/index.js", "typings": "./src/index.d.ts", "types": "./dist/index.d.ts" diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/highLevelApis/PaymentManager/PaymentManager.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/highLevelApis/PaymentManager/PaymentManager.ts index 9a835b8e8..961c1ca42 100644 --- a/packages/networks/src/networks/vNaga/LitChainClient/apis/highLevelApis/PaymentManager/PaymentManager.ts +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/highLevelApis/PaymentManager/PaymentManager.ts @@ -36,6 +36,15 @@ import { depositForUser } from '../../rawContractApis/ledger/write/depositForUse import { requestWithdraw } from '../../rawContractApis/ledger/write/requestWithdraw'; import { withdraw } from '../../rawContractApis/ledger/write/withdraw'; import { LitTxVoid } from '../../types'; +import { getPayers } from '../../rawContractApis/paymentDelegation/read/getPayers'; +import { getUsers } from '../../rawContractApis/paymentDelegation/read/getUsers'; +import { getRestriction, Restriction } from '../../rawContractApis/paymentDelegation/read/getRestriction'; +import { getPayersAndRestrictions } from '../../rawContractApis/paymentDelegation/read/getPayersAndRestrictions'; +import { delegatePayments } from '../../rawContractApis/paymentDelegation/write/delegatePayments'; +import { undelegatePayments } from '../../rawContractApis/paymentDelegation/write/undelegatePayments'; +import { delegatePaymentsBatch } from '../../rawContractApis/paymentDelegation/write/delegatePaymentsBatch'; +import { undelegatePaymentsBatch } from '../../rawContractApis/paymentDelegation/write/undelegatePaymentsBatch'; +import { setRestriction } from '../../rawContractApis/paymentDelegation/write/setRestriction'; export interface PaymentBalance { /** Total balance including pending withdrawals */ @@ -256,4 +265,188 @@ export class PaymentManager { withdrawRequest, }; } + + // ========== Payment Delegation Methods ========== + + /** + * Delegate payments to a user + * @param params - Parameters containing user address + * @returns Transaction result + */ + async delegatePayments(params: { userAddress: string }): Promise { + logger.debug('Delegating payments to user', { userAddress: params.userAddress }); + + return await delegatePayments( + { userAddress: params.userAddress }, + this.networkContext, + this.accountOrWalletClient + ); + } + + /** + * Undelegate payments from a user + * @param params - Parameters containing user address + * @returns Transaction result + */ + async undelegatePayments(params: { userAddress: string }): Promise { + logger.debug('Undelegating payments from user', { userAddress: params.userAddress }); + + return await undelegatePayments( + { userAddress: params.userAddress }, + this.networkContext, + this.accountOrWalletClient + ); + } + + /** + * Delegate payments to multiple users + * @param params - Parameters containing array of user addresses + * @returns Transaction result + */ + async delegatePaymentsBatch(params: { userAddresses: string[] }): Promise { + logger.debug('Delegating payments to multiple users', { userAddresses: params.userAddresses }); + + return await delegatePaymentsBatch( + { userAddresses: params.userAddresses }, + this.networkContext, + this.accountOrWalletClient + ); + } + + /** + * Undelegate payments from multiple users + * @param params - Parameters containing array of user addresses + * @returns Transaction result + */ + async undelegatePaymentsBatch(params: { userAddresses: string[] }): Promise { + logger.debug('Undelegating payments from multiple users', { userAddresses: params.userAddresses }); + + return await undelegatePaymentsBatch( + { userAddresses: params.userAddresses }, + this.networkContext, + this.accountOrWalletClient + ); + } + + /** + * Set payment restriction for the caller + * @param params - Restriction parameters + * @returns Transaction result + */ + async setRestriction(params: { + totalMaxPrice: string; + requestsPerPeriod: string; + periodSeconds: string; + }): Promise { + logger.debug('Setting payment restriction', params); + + return await setRestriction( + { + restriction: { + totalMaxPrice: BigInt(params.totalMaxPrice), + requestsPerPeriod: BigInt(params.requestsPerPeriod), + periodSeconds: BigInt(params.periodSeconds), + } + }, + this.networkContext, + this.accountOrWalletClient + ); + } + + /** + * Get payers for a user + * @param params - Parameters containing user address + * @returns Array of payer addresses + */ + async getPayers(params: { userAddress: string }): Promise { + logger.debug('Getting payers for user', { userAddress: params.userAddress }); + + return await getPayers( + { userAddress: params.userAddress }, + this.networkContext, + this.accountOrWalletClient + ); + } + + /** + * Get users for a payer + * @param params - Parameters containing payer address + * @returns Array of user addresses + */ + async getUsers(params: { payerAddress: string }): Promise { + logger.debug('Getting users for payer', { payerAddress: params.payerAddress }); + + return await getUsers( + { payerAddress: params.payerAddress }, + this.networkContext, + this.accountOrWalletClient + ); + } + + /** + * Get restriction for a payer + * @param params - Parameters containing payer address + * @returns Restriction object + */ + async getRestriction(params: { payerAddress: string }): Promise<{ + totalMaxPrice: string; + requestsPerPeriod: string; + periodSeconds: string; + raw: Restriction; + }> { + logger.debug('Getting restriction for payer', { payerAddress: params.payerAddress }); + + const restriction = await getRestriction( + { payerAddress: params.payerAddress }, + this.networkContext, + this.accountOrWalletClient + ); + + return { + totalMaxPrice: restriction.totalMaxPrice.toString(), + requestsPerPeriod: restriction.requestsPerPeriod.toString(), + periodSeconds: restriction.periodSeconds.toString(), + raw: restriction, + }; + } + + /** + * Get payers and restrictions for multiple users + * @param params - Parameters containing array of user addresses + * @returns Object containing arrays of payers and restrictions + */ + async getPayersAndRestrictions(params: { userAddresses: string[] }): Promise<{ + payers: string[][]; + restrictions: Array>; + raw: { + payers: string[][]; + restrictions: Restriction[][]; + }; + }> { + logger.debug('Getting payers and restrictions for users', { userAddresses: params.userAddresses }); + + const result = await getPayersAndRestrictions( + { userAddresses: params.userAddresses }, + this.networkContext, + this.accountOrWalletClient + ); + + const formattedRestrictions = result.restrictions.map(userRestrictions => + userRestrictions.map(restriction => ({ + totalMaxPrice: restriction.totalMaxPrice.toString(), + requestsPerPeriod: restriction.requestsPerPeriod.toString(), + periodSeconds: restriction.periodSeconds.toString(), + })) + ); + + return { + payers: result.payers, + restrictions: formattedRestrictions, + raw: result, + }; + } } \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getPayers.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getPayers.ts new file mode 100644 index 000000000..a6a2eea26 --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getPayers.ts @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; + +// Schema for validating the request +const getPayersSchema = z.object({ + userAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address'), +}); + +export type GetPayersRequest = z.infer; + +/** + * Get payers for a user from the PaymentDelegation contract + * @param request - Object containing userAddress + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Array of payer addresses + */ +export async function getPayers( + request: GetPayersRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = getPayersSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const payers = await paymentDelegationContract.read.getPayers([validatedRequest.userAddress]); + return payers; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getPayersAndRestrictions.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getPayersAndRestrictions.ts new file mode 100644 index 000000000..12e35185d --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getPayersAndRestrictions.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; +import { Restriction } from './getRestriction'; + +// Schema for validating the request +const getPayersAndRestrictionsSchema = z.object({ + userAddresses: z.array(z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address')), +}); + +export type GetPayersAndRestrictionsRequest = z.infer; + +export interface PayersAndRestrictionsResponse { + payers: string[][]; + restrictions: Restriction[][]; +} + +/** + * Get payers and restrictions for multiple users from the PaymentDelegation contract + * @param request - Object containing array of userAddresses + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Object containing arrays of payers and restrictions + */ +export async function getPayersAndRestrictions( + request: GetPayersAndRestrictionsRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = getPayersAndRestrictionsSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const [payers, restrictions] = await paymentDelegationContract.read.getPayersAndRestrictions([validatedRequest.userAddresses]); + return { payers, restrictions }; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getRestriction.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getRestriction.ts new file mode 100644 index 000000000..eeed14667 --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getRestriction.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; + +// Schema for validating the request +const getRestrictionSchema = z.object({ + payerAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address'), +}); + +export type GetRestrictionRequest = z.infer; + +export interface Restriction { + totalMaxPrice: bigint; + requestsPerPeriod: bigint; + periodSeconds: bigint; +} + +/** + * Get restriction for a payer from the PaymentDelegation contract + * @param request - Object containing payerAddress + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Restriction object + */ +export async function getRestriction( + request: GetRestrictionRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = getRestrictionSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const restriction = await paymentDelegationContract.read.getRestriction([validatedRequest.payerAddress]); + return restriction; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getUsers.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getUsers.ts new file mode 100644 index 000000000..f6a640aba --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/read/getUsers.ts @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; + +// Schema for validating the request +const getUsersSchema = z.object({ + payerAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address'), +}); + +export type GetUsersRequest = z.infer; + +/** + * Get users for a payer from the PaymentDelegation contract + * @param request - Object containing payerAddress + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Array of user addresses + */ +export async function getUsers( + request: GetUsersRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = getUsersSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const users = await paymentDelegationContract.read.getUsers([validatedRequest.payerAddress]); + return users; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/delegatePayments.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/delegatePayments.ts new file mode 100644 index 000000000..0ec23bd25 --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/delegatePayments.ts @@ -0,0 +1,52 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; +import { LitTxVoid } from '../../../types'; +import { callWithAdjustedOverrides } from '../../../utils/callWithAdjustedOverrides'; +import { decodeLogs } from '../../../utils/decodeLogs'; + +// Schema for validating the request +const delegatePaymentsSchema = z.object({ + userAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address'), +}); + +export type DelegatePaymentsRequest = z.infer; + +/** + * Delegate payments to a user + * @param request - Object containing userAddress + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Transaction result with hash, receipt and decoded logs + */ +export async function delegatePayments( + request: DelegatePaymentsRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = delegatePaymentsSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract, publicClient } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const hash = await callWithAdjustedOverrides( + paymentDelegationContract, + 'delegatePayments', + [validatedRequest.userAddress] + ); + + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + + const decodedLogs = await decodeLogs( + receipt.logs, + networkCtx, + accountOrWalletClient + ); + + return { hash, receipt, decodedLogs }; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/delegatePaymentsBatch.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/delegatePaymentsBatch.ts new file mode 100644 index 000000000..976dae7cb --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/delegatePaymentsBatch.ts @@ -0,0 +1,52 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; +import { LitTxVoid } from '../../../types'; +import { callWithAdjustedOverrides } from '../../../utils/callWithAdjustedOverrides'; +import { decodeLogs } from '../../../utils/decodeLogs'; + +// Schema for validating the request +const delegatePaymentsBatchSchema = z.object({ + userAddresses: z.array(z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address')), +}); + +export type DelegatePaymentsBatchRequest = z.infer; + +/** + * Delegate payments to multiple users in batch + * @param request - Object containing array of userAddresses + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Transaction result with hash, receipt and decoded logs + */ +export async function delegatePaymentsBatch( + request: DelegatePaymentsBatchRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = delegatePaymentsBatchSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract, publicClient } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const hash = await callWithAdjustedOverrides( + paymentDelegationContract, + 'delegatePaymentsBatch', + [validatedRequest.userAddresses] + ); + + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + + const decodedLogs = await decodeLogs( + receipt.logs, + networkCtx, + accountOrWalletClient + ); + + return { hash, receipt, decodedLogs }; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/setRestriction.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/setRestriction.ts new file mode 100644 index 000000000..aa61a8595 --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/setRestriction.ts @@ -0,0 +1,56 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; +import { LitTxVoid } from '../../../types'; +import { callWithAdjustedOverrides } from '../../../utils/callWithAdjustedOverrides'; +import { decodeLogs } from '../../../utils/decodeLogs'; + +// Schema for validating the request +const setRestrictionSchema = z.object({ + restriction: z.object({ + totalMaxPrice: z.bigint(), + requestsPerPeriod: z.bigint(), + periodSeconds: z.bigint(), + }), +}); + +export type SetRestrictionRequest = z.infer; + +/** + * Set payment restriction for the caller + * @param request - Object containing restriction parameters + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Transaction result with hash, receipt and decoded logs + */ +export async function setRestriction( + request: SetRestrictionRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = setRestrictionSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract, publicClient } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const hash = await callWithAdjustedOverrides( + paymentDelegationContract, + 'setRestriction', + [validatedRequest.restriction] + ); + + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + + const decodedLogs = await decodeLogs( + receipt.logs, + networkCtx, + accountOrWalletClient + ); + + return { hash, receipt, decodedLogs }; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/undelegatePayments.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/undelegatePayments.ts new file mode 100644 index 000000000..a82c8ac95 --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/undelegatePayments.ts @@ -0,0 +1,52 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; +import { LitTxVoid } from '../../../types'; +import { callWithAdjustedOverrides } from '../../../utils/callWithAdjustedOverrides'; +import { decodeLogs } from '../../../utils/decodeLogs'; + +// Schema for validating the request +const undelegatePaymentsSchema = z.object({ + userAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address'), +}); + +export type UndelegatePaymentsRequest = z.infer; + +/** + * Undelegate payments from a user + * @param request - Object containing userAddress + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Transaction result with hash, receipt and decoded logs + */ +export async function undelegatePayments( + request: UndelegatePaymentsRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = undelegatePaymentsSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract, publicClient } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const hash = await callWithAdjustedOverrides( + paymentDelegationContract, + 'undelegatePayments', + [validatedRequest.userAddress] + ); + + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + + const decodedLogs = await decodeLogs( + receipt.logs, + networkCtx, + accountOrWalletClient + ); + + return { hash, receipt, decodedLogs }; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/undelegatePaymentsBatch.ts b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/undelegatePaymentsBatch.ts new file mode 100644 index 000000000..c0647eafa --- /dev/null +++ b/packages/networks/src/networks/vNaga/LitChainClient/apis/rawContractApis/paymentDelegation/write/undelegatePaymentsBatch.ts @@ -0,0 +1,52 @@ +import { z } from 'zod'; +import { logger } from '../../../../../../shared/logger'; +import { DefaultNetworkConfig } from '../../../../../interfaces/NetworkContext'; +import { createContractsManager } from '../../../../contract-manager/createContractsManager'; +import { ExpectedAccountOrWalletClient } from '../../../../contract-manager/createContractsManager'; +import { LitTxVoid } from '../../../types'; +import { callWithAdjustedOverrides } from '../../../utils/callWithAdjustedOverrides'; +import { decodeLogs } from '../../../utils/decodeLogs'; + +// Schema for validating the request +const undelegatePaymentsBatchSchema = z.object({ + userAddresses: z.array(z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address')), +}); + +export type UndelegatePaymentsBatchRequest = z.infer; + +/** + * Undelegate payments from multiple users in batch + * @param request - Object containing array of userAddresses + * @param networkCtx - Network context for contract interactions + * @param accountOrWalletClient - Account or wallet client for the transaction + * @returns Transaction result with hash, receipt and decoded logs + */ +export async function undelegatePaymentsBatch( + request: UndelegatePaymentsBatchRequest, + networkCtx: DefaultNetworkConfig, + accountOrWalletClient: ExpectedAccountOrWalletClient +): Promise { + const validatedRequest = undelegatePaymentsBatchSchema.parse(request); + logger.debug({ validatedRequest }); + + const { paymentDelegationContract, publicClient } = createContractsManager( + networkCtx, + accountOrWalletClient + ); + + const hash = await callWithAdjustedOverrides( + paymentDelegationContract, + 'undelegatePaymentsBatch', + [validatedRequest.userAddresses] + ); + + const receipt = await publicClient.waitForTransactionReceipt({ hash }); + + const decodedLogs = await decodeLogs( + receipt.logs, + networkCtx, + accountOrWalletClient + ); + + return { hash, receipt, decodedLogs }; +} \ No newline at end of file diff --git a/packages/networks/src/networks/vNaga/LitChainClient/contract-manager/createContractsManager.ts b/packages/networks/src/networks/vNaga/LitChainClient/contract-manager/createContractsManager.ts index 63c16d78f..4b52a2d5f 100644 --- a/packages/networks/src/networks/vNaga/LitChainClient/contract-manager/createContractsManager.ts +++ b/packages/networks/src/networks/vNaga/LitChainClient/contract-manager/createContractsManager.ts @@ -174,11 +174,29 @@ export const createContractsManager = ( contractData.Ledger.methods.requestWithdraw, contractData.Ledger.methods.stableBalance, contractData.Ledger.methods.userWithdrawDelay, + contractData.Ledger.methods.withdraw, ...contractData.Ledger.events, ], client: { public: publicClient, wallet: walletClient }, }); + const paymentDelegationContract = getContract({ + address: contractData.PaymentDelegation.address, + abi: [ + contractData.PaymentDelegation.methods.delegatePayments, + contractData.PaymentDelegation.methods.delegatePaymentsBatch, + contractData.PaymentDelegation.methods.getPayers, + contractData.PaymentDelegation.methods.getPayersAndRestrictions, + contractData.PaymentDelegation.methods.getRestriction, + contractData.PaymentDelegation.methods.getUsers, + contractData.PaymentDelegation.methods.setRestriction, + contractData.PaymentDelegation.methods.undelegatePayments, + contractData.PaymentDelegation.methods.undelegatePaymentsBatch, + ...contractData.PaymentDelegation.events, + ], + client: { public: publicClient, wallet: walletClient }, + }); + // ---------- End of all your contracts ---------- return { pkpNftContract, @@ -188,6 +206,7 @@ export const createContractsManager = ( pkpPermissionsContract, pubkeyRouterContract, ledgerContract, + paymentDelegationContract, publicClient, walletClient, };