Skip to content

Commit e8692e1

Browse files
committed
feat(e2e): payment delegation flow
1 parent 278fd45 commit e8692e1

File tree

4 files changed

+83
-22
lines changed

4 files changed

+83
-22
lines changed

packages/e2e/src/helper/createEnvVars.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const testEnv: Record<
1919

2020
export function createEnvVars(): EnvVars {
2121
// 1. Get network string
22-
const network = process.env['NETWORK']!!;
22+
const network = process.env['NETWORK']!!;
2323

2424
if (!network || !supportedNetworks.includes(network as any)) {
2525
throw new Error(

packages/e2e/src/helper/createTestAccount.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type CreateTestAccountOpts = {
1616
fundPKPLedger: boolean;
1717
sponsor?: {
1818
restrictions: {
19-
totalMaxPriceInEth: string;
19+
totalMaxPriceInWei: string;
2020
requestsPerPeriod: string;
2121
periodSeconds: string;
2222
};
@@ -153,17 +153,18 @@ export async function createTestAccount(
153153
// 2. Set Restrictions
154154

155155
// Convert to Wei using Viem
156-
const wei = parseEther(opts.sponsor.restrictions.totalMaxPriceInEth);
157-
158-
console.log(`- Setting sponsorship restrictions:`, {
159-
totalMaxPriceInEth: opts.sponsor.restrictions.totalMaxPriceInEth,
160-
totalMaxPriceInWei: wei.toString(),
161-
requestsPerPeriod: opts.sponsor.restrictions.requestsPerPeriod,
162-
periodSeconds: opts.sponsor.restrictions.periodSeconds,
163-
});
156+
// const wei = parseEther(opts.sponsor.restrictions.totalMaxPriceInEth);
157+
158+
// console.log(`- Setting sponsorship restrictions:`, {
159+
// totalMaxPriceInEth: opts.sponsor.restrictions.totalMaxPriceInEth,
160+
// totalMaxPriceInWei: wei.toString(),
161+
// requestsPerPeriod: opts.sponsor.restrictions.requestsPerPeriod,
162+
// periodSeconds: opts.sponsor.restrictions.periodSeconds,
163+
// });
164164
try {
165165
const tx = await personPaymentManager.setRestriction({
166-
totalMaxPrice: wei.toString(),
166+
// totalMaxPrice: wei.toString(),
167+
totalMaxPrice: opts.sponsor.restrictions.totalMaxPriceInWei,
167168
requestsPerPeriod: opts.sponsor.restrictions.requestsPerPeriod,
168169
periodSeconds: opts.sponsor.restrictions.periodSeconds,
169170
});

packages/e2e/src/tickets/delegation.spec.ts

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@ describe('payment delegation test', () => {
2121
bobAccount = await createTestAccount(testEnv, {
2222
label: 'Bob',
2323
fundAccount: true,
24-
fundLedger: true,
24+
hasEoaAuthContext: true,
25+
fundLedger: false,
2526
hasPKP: true,
26-
fundPKP: true,
27-
fundPKPLedger: true,
27+
fundPKP: false,
28+
hasPKPAuthContext: false,
29+
fundPKPLedger: false,
2830
});
2931

32+
console.log('bobAccount:', bobAccount);
33+
3034
if (!bobAccount.pkp?.ethAddress) {
3135
throw new Error("Bob's PKP does not have an ethAddress");
3236
}
@@ -35,27 +39,74 @@ describe('payment delegation test', () => {
3539
alice = await createTestAccount(testEnv, {
3640
label: 'Alice',
3741
fundAccount: true,
38-
fundLedger: false,
42+
fundLedger: true,
3943
hasPKP: true,
4044
fundPKP: true,
4145
fundPKPLedger: true,
4246
sponsor: {
4347
restrictions: {
44-
totalMaxPriceInEth: '0.05',
48+
totalMaxPriceInWei: '1000000000000000000',
4549
requestsPerPeriod: '100',
4650
periodSeconds: '5',
4751
},
48-
userAddresses: [bobAccount.pkp.ethAddress],
52+
userAddresses: [bobAccount.account.address],
4953
},
5054
});
5155

52-
// 3. Now, Bob tries to execute JS using Alice's sponsorship
53-
const res = await testEnv.litClient.chain.ethereum.pkpSign({
54-
authContext: bobAccount.pkpAuthContext!,
56+
// 3. Take a snapshot of Alice's Ledger balance before Bob's request
57+
const aliceBeforeBalance = await testEnv.masterPaymentManager.getBalance({
58+
userAddress: alice.account.address,
59+
});
60+
61+
console.log(
62+
"[BEFORE] Alice's Ledger balance before Bob's request:",
63+
aliceBeforeBalance
64+
);
65+
66+
// 3. Now, Bob tries to sign with his PKP using Alice's sponsorship
67+
await testEnv.litClient.chain.ethereum.pkpSign({
68+
authContext: bobAccount.eoaAuthContext!,
5569
pubKey: bobAccount.pkp?.pubkey!,
5670
toSign: 'Hello, world!',
71+
userMaxPrice: 200000000000000000n, // 0.2 ETH in Wei
72+
});
73+
74+
// 4. Finally, check that Alice's Ledger balance has decreased
75+
const aliceBalanceAfter = await testEnv.masterPaymentManager.getBalance({
76+
userAddress: alice.account.address,
5777
});
5878

59-
console.log('res:', res);
79+
console.log(
80+
"[AFTER] Alice's Ledger balance after Bob's request:",
81+
aliceBalanceAfter
82+
);
83+
84+
expect(BigInt(aliceBalanceAfter.raw.availableBalance)).toBeLessThan(
85+
BigInt(aliceBeforeBalance.raw.availableBalance)
86+
);
87+
88+
// 5. Now, Alice removes Bob from her sponsorship
89+
await alice.paymentManager!.undelegatePaymentsBatch({
90+
userAddresses: [bobAccount.account.address],
91+
});
92+
93+
// 6. Bob should now fail to sign with his PKP due to lack of sponsorship
94+
let didFail = false;
95+
try {
96+
await testEnv.litClient.chain.ethereum.pkpSign({
97+
authContext: bobAccount.eoaAuthContext!,
98+
pubKey: bobAccount.pkp?.pubkey!,
99+
toSign: 'Hello again, world!',
100+
userMaxPrice: 200000000000000000n, // 0.2 ETH in Wei
101+
});
102+
} catch (e) {
103+
didFail = true;
104+
console.log(
105+
"As expected, Bob's PKP sign failed after Alice removed sponsorship:",
106+
e
107+
);
108+
}
109+
110+
expect(didFail).toBe(true);
60111
});
61112
});

packages/networks/src/networks/vNaga/shared/managers/session-manager/issueSessionFromContext.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,19 @@ export const issueSessionFromContext = async (params: {
9797
// console.log('🔄 _userMaxPrices', _userMaxPrices);
9898

9999
_userMaxPrices.forEach(({ url: nodeAddress, price }) => {
100+
// ❗️❗️ TEMPORARY FIX: Convert to hex client-side so the node sees the
101+
// intended wei cap until it supports decimal parsing.
102+
// Reason: the node deserialises via `serde_json` into
103+
// `ethers::types::U256`, which treats bare strings as hex. Sending our
104+
// decimal bigint (e.g. "250000000000000000") therefore turns into the much
105+
// larger 0x2500... amount.
106+
const priceInWei = price;
107+
const maxPriceHex = `0x${priceInWei.toString(16)}`;
108+
100109
const toSign: SessionSigningTemplate = {
101110
...sessionSigningTemplate,
102111
nodeAddress,
103-
maxPrice: price.toString(),
112+
maxPrice: maxPriceHex,
104113
};
105114

106115
// console.log(`Setting maxprice for ${nodeAddress} to `, price.toString());

0 commit comments

Comments
 (0)