Skip to content

Commit 5de5442

Browse files
fix all the things
1 parent 94da146 commit 5de5442

File tree

6 files changed

+195
-77
lines changed

6 files changed

+195
-77
lines changed

packages/thirdweb/src/exports/wallets/smart.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ export {
3535
ENTRYPOINT_ADDRESS_v0_7,
3636
DEFAULT_ACCOUNT_FACTORY_V0_6,
3737
DEFAULT_ACCOUNT_FACTORY_V0_7,
38+
TokenPaymaster,
3839
} from "../../wallets/smart/lib/constants.js";

packages/thirdweb/src/wallets/smart/index.ts

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
} from "./lib/calls.js";
4747
import {
4848
ENTRYPOINT_ADDRESS_v0_6,
49+
ENTRYPOINT_ADDRESS_v0_7,
4950
getDefaultAccountFactory,
5051
getEntryPointVersion,
5152
} from "./lib/constants.js";
@@ -120,6 +121,17 @@ export async function connectSmartWallet(
120121
}
121122
}
122123

124+
if (
125+
options.overrides?.tokenPaymaster &&
126+
!options.overrides?.entrypointAddress
127+
) {
128+
// if token paymaster is set, but no entrypoint address, set the entrypoint address to v0.7
129+
options.overrides = {
130+
...options.overrides,
131+
entrypointAddress: ENTRYPOINT_ADDRESS_v0_7,
132+
};
133+
}
134+
123135
const factoryAddress =
124136
options.factoryAddress ??
125137
getDefaultAccountFactory(options.overrides?.entrypointAddress);
@@ -200,8 +212,8 @@ export async function disconnectSmartWallet(
200212
async function createSmartAccount(
201213
options: SmartAccountOptions,
202214
): Promise<Account> {
203-
let erc20Paymaster = options.overrides?.tokenPaymaster;
204-
if (erc20Paymaster && typeof erc20Paymaster === "string") {
215+
const erc20Paymaster = options.overrides?.tokenPaymaster;
216+
if (erc20Paymaster) {
205217
if (
206218
getEntryPointVersion(
207219
options.overrides?.entrypointAddress || ENTRYPOINT_ADDRESS_v0_6,
@@ -211,32 +223,6 @@ async function createSmartAccount(
211223
"Token paymaster is only supported for entrypoint version v0.7",
212224
);
213225
}
214-
switch (erc20Paymaster) {
215-
case "BASE_USDC":
216-
erc20Paymaster = {
217-
chainId: 8453,
218-
paymasterAddress: "0x2222f2738BE6bB7aA0Bfe4AEeAf2908172CF5539",
219-
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
220-
balanceStorageSlot: 9,
221-
};
222-
break;
223-
case "CELO_CUSD":
224-
erc20Paymaster = {
225-
chainId: 42220,
226-
paymasterAddress: "0x3feA3c5744D715ff46e91C4e5C9a94426DfF2aF9",
227-
tokenAddress: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
228-
balanceStorageSlot: 9,
229-
};
230-
break;
231-
case "LISK_LSK":
232-
erc20Paymaster = {
233-
chainId: 1135,
234-
paymasterAddress: "0x9eb8cf7fBa5ed9EeDCC97a0d52254cc0e9B1AC25",
235-
tokenAddress: "0xac485391EB2d7D88253a7F1eF18C37f4242D1A24",
236-
balanceStorageSlot: 9,
237-
};
238-
break;
239-
}
240226
}
241227

242228
const { accountContract } = options;

packages/thirdweb/src/wallets/smart/lib/constants.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Chain } from "../../../chains/types.js";
22
import { getAddress } from "../../../utils/address.js";
33
import { getThirdwebDomains } from "../../../utils/domains.js";
4+
import type { TokenPaymasterConfig } from "../types.js";
45

56
export const DUMMY_SIGNATURE =
67
"0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";
@@ -17,6 +18,28 @@ export const ENTRYPOINT_ADDRESS_v0_7 =
1718

1819
export const MANAGED_ACCOUNT_GAS_BUFFER = 50000n;
1920

21+
export type PAYMASTERS = "BASE_USDC" | "CELO_CUSD" | "LISK_LSK";
22+
export const TokenPaymaster: Record<PAYMASTERS, TokenPaymasterConfig> = {
23+
BASE_USDC: {
24+
chainId: 8453,
25+
paymasterAddress: "0x2222f2738BE6bB7aA0Bfe4AEeAf2908172CF5539",
26+
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
27+
balanceStorageSlot: 9n,
28+
},
29+
CELO_CUSD: {
30+
chainId: 42220,
31+
paymasterAddress: "0x3feA3c5744D715ff46e91C4e5C9a94426DfF2aF9",
32+
tokenAddress: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
33+
balanceStorageSlot: 9n,
34+
},
35+
LISK_LSK: {
36+
chainId: 1135,
37+
paymasterAddress: "0x9eb8cf7fBa5ed9EeDCC97a0d52254cc0e9B1AC25",
38+
tokenAddress: "0xac485391EB2d7D88253a7F1eF18C37f4242D1A24",
39+
balanceStorageSlot: 9n,
40+
},
41+
};
42+
2043
/*
2144
* @internal
2245
*/

packages/thirdweb/src/wallets/smart/lib/userop.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { concat, encodePacked, keccak256, toBytes, toHex } from "viem";
1+
import { maxUint96 } from "ox/Solidity";
2+
import { concat, keccak256, toHex } from "viem";
23
import type { Chain } from "../../../chains/types.js";
34
import type { ThirdwebClient } from "../../../client/client.js";
45
import {
@@ -13,6 +14,7 @@ import { encode } from "../../../transaction/actions/encode.js";
1314
import { toSerializableTransaction } from "../../../transaction/actions/to-serializable-transaction.js";
1415
import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js";
1516
import type { TransactionReceipt } from "../../../transaction/types.js";
17+
import { encodeAbiParameters } from "../../../utils/abi/encodeAbiParameters.js";
1618
import { isContractDeployed } from "../../../utils/bytecode/is-contract-deployed.js";
1719
import type { Hex } from "../../../utils/encoding/hex.js";
1820
import { hexToBytes } from "../../../utils/encoding/to-bytes.js";
@@ -23,7 +25,6 @@ import type {
2325
BundlerOptions,
2426
PaymasterResult,
2527
SmartWalletOptions,
26-
TokenPaymasterConfig,
2728
UserOperationV06,
2829
UserOperationV07,
2930
} from "../types.js";
@@ -364,26 +365,21 @@ async function populateUserOp_v0_7(args: {
364365
// otherwise fallback to bundler for gas limits
365366
const stateOverrides = overrides?.tokenPaymaster
366367
? {
367-
[(overrides.tokenPaymaster as TokenPaymasterConfig).tokenAddress]: {
368+
[overrides.tokenPaymaster.tokenAddress]: {
368369
stateDiff: {
369370
[keccak256(
370-
encodePacked(
371-
["address", "uint256"],
371+
encodeAbiParameters(
372+
[{ type: "address" }, { type: "uint256" }],
372373
[
373374
accountContract.address,
374-
BigInt(
375-
(overrides?.tokenPaymaster as TokenPaymasterConfig)
376-
.balanceStorageSlot,
377-
),
375+
overrides.tokenPaymaster.balanceStorageSlot,
378376
],
379377
),
380-
)]: toBytes(toHex(BigInt(2) * BigInt(96) - BigInt(1)), {
381-
size: 32,
382-
}),
378+
)]: toHex(maxUint96, { size: 32 }),
383379
},
384380
},
385381
}
386-
: {};
382+
: undefined;
387383
const estimates = await estimateUserOpGas(
388384
{
389385
userOp: partialOp,
@@ -395,10 +391,10 @@ async function populateUserOp_v0_7(args: {
395391
partialOp.verificationGasLimit = estimates.verificationGasLimit;
396392
partialOp.preVerificationGas = estimates.preVerificationGas;
397393
partialOp.paymasterPostOpGasLimit = overrides?.tokenPaymaster
398-
? 500_000n
399-
: paymasterResult.paymasterPostOpGasLimit || 0n;
394+
? 500000n // TODO: estimate this better, needed if there's an extra swap needed in the paymaster
395+
: estimates.paymasterPostOpGasLimit || 0n;
400396
partialOp.paymasterVerificationGasLimit =
401-
paymasterResult.paymasterVerificationGasLimit || 0n;
397+
estimates.paymasterVerificationGasLimit || 0n;
402398
// need paymaster to re-sign after estimates
403399
const paymasterResult2 = (await getPaymasterAndData({
404400
userOp: partialOp,
Lines changed: 138 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,162 @@
1-
import { base } from "src/chains/chain-definitions/base.js";
2-
import { sendTransaction } from "src/transaction/actions/send-transaction.js";
3-
import { prepareTransaction } from "src/transaction/prepare-transaction.js";
4-
import { beforeAll, describe, expect, it } from "vitest";
1+
import { describe, expect, it } from "vitest";
52
import { TEST_CLIENT } from "../../../test/src/test-clients.js";
6-
import { setThirdwebDomains } from "../../utils/domains.js";
7-
import type { Account } from "../interfaces/wallet.js";
3+
import { base } from "../../chains/chain-definitions/base.js";
4+
import { celo } from "../../chains/chain-definitions/celo.js";
5+
import { defineChain } from "../../chains/utils.js";
6+
import { sendTransaction } from "../../transaction/actions/send-transaction.js";
7+
import { prepareTransaction } from "../../transaction/prepare-transaction.js";
8+
import type { Address } from "../../utils/address.js";
89
import { privateKeyToAccount } from "../private-key.js";
10+
import { getWalletBalance } from "../utils/getWalletBalance.js";
11+
import { TokenPaymaster } from "./lib/constants.js";
912
import { smartWallet } from "./smart-wallet.js";
1013

11-
let personalAccount: Account;
12-
1314
const client = TEST_CLIENT;
1415

1516
describe.runIf(process.env.TW_SECRET_KEY).skip.sequential(
16-
"SmartWallet policy tests",
17+
"SmartWallet token paymaster tests",
1718
{
1819
retry: 0,
1920
timeout: 240_000,
2021
},
2122
() => {
22-
beforeAll(async () => {
23-
setThirdwebDomains({
24-
rpc: "rpc.thirdweb-dev.com",
25-
storage: "storage.thirdweb-dev.com",
26-
bundler: "bundler.thirdweb-dev.com",
27-
});
28-
personalAccount = await privateKeyToAccount({
23+
it.skip("should send a transaction with base usdc", async () => {
24+
const chain = base;
25+
const tokenPaymaster = TokenPaymaster.BASE_USDC;
26+
const personalAccount = privateKeyToAccount({
2927
client,
3028
privateKey:
3129
"edf401e8ddbb743f3353b055081cb220ce4c5c04e08da162d86e0dba7c6f0f01", // 0xa470E7c88611364f55B2d7912613e10AF2eA918D
3230
});
31+
const wallet = smartWallet({
32+
chain,
33+
gasless: true,
34+
overrides: {
35+
tokenPaymaster,
36+
},
37+
});
38+
const smartAccount = await wallet.connect({
39+
client: TEST_CLIENT,
40+
personalAccount,
41+
});
42+
const smartWalletAddress = smartAccount.address as Address;
43+
console.log("smartWalletAddress", smartWalletAddress);
44+
console.log(
45+
"balance before",
46+
await getWalletBalance({
47+
address: smartAccount.address,
48+
chain: chain,
49+
client,
50+
tokenAddress: tokenPaymaster.tokenAddress,
51+
}),
52+
);
53+
const tx = prepareTransaction({
54+
client,
55+
chain,
56+
to: smartAccount.address,
57+
value: 0n,
58+
});
59+
const receipt = await sendTransaction({
60+
transaction: tx,
61+
account: smartAccount,
62+
});
63+
expect(receipt.transactionHash).toBeDefined();
64+
console.log(
65+
"balance after",
66+
await getWalletBalance({
67+
address: smartAccount.address,
68+
chain: chain,
69+
client,
70+
tokenAddress: tokenPaymaster.tokenAddress,
71+
}),
72+
);
3373
});
3474

35-
it("can self transfer with BASE_USDC", async () => {
75+
it.skip("should send a transaction with base celo", async () => {
76+
const chain = celo;
77+
const tokenPaymaster = TokenPaymaster.CELO_CUSD;
78+
const personalAccount = privateKeyToAccount({
79+
client,
80+
privateKey:
81+
"edf401e8ddbb743f3353b055081cb220ce4c5c04e08da162d86e0dba7c6f0f01", // 0xa470E7c88611364f55B2d7912613e10AF2eA918D
82+
});
3683
const wallet = smartWallet({
37-
chain: base,
84+
chain,
3885
gasless: true,
3986
overrides: {
40-
tokenPaymaster: "BASE_USDC",
87+
tokenPaymaster,
4188
},
4289
});
4390
const smartAccount = await wallet.connect({
4491
client: TEST_CLIENT,
4592
personalAccount,
4693
});
94+
const smartWalletAddress = smartAccount.address as Address;
95+
console.log("smartWalletAddress", smartWalletAddress);
96+
console.log(
97+
"balance before",
98+
await getWalletBalance({
99+
address: smartAccount.address,
100+
chain: chain,
101+
client,
102+
tokenAddress: tokenPaymaster.tokenAddress,
103+
}),
104+
);
105+
const tx = prepareTransaction({
106+
client,
107+
chain,
108+
to: smartAccount.address,
109+
value: 0n,
110+
});
111+
const receipt = await sendTransaction({
112+
transaction: tx,
113+
account: smartAccount,
114+
});
115+
expect(receipt.transactionHash).toBeDefined();
116+
console.log(
117+
"balance after",
118+
await getWalletBalance({
119+
address: smartAccount.address,
120+
chain: chain,
121+
client,
122+
tokenAddress: tokenPaymaster.tokenAddress,
123+
}),
124+
);
125+
});
47126

48-
console.log("smartAccount", smartAccount.address);
49-
127+
it("should send a transaction with base lisk", async () => {
128+
const chain = defineChain(1135);
129+
const tokenPaymaster = TokenPaymaster.LISK_LSK;
130+
const personalAccount = privateKeyToAccount({
131+
client,
132+
privateKey:
133+
"edf401e8ddbb743f3353b055081cb220ce4c5c04e08da162d86e0dba7c6f0f01", // 0xa470E7c88611364f55B2d7912613e10AF2eA918D
134+
});
135+
const wallet = smartWallet({
136+
chain,
137+
gasless: true,
138+
overrides: {
139+
tokenPaymaster,
140+
},
141+
});
142+
const smartAccount = await wallet.connect({
143+
client: TEST_CLIENT,
144+
personalAccount,
145+
});
146+
const smartWalletAddress = smartAccount.address as Address;
147+
console.log("smartWalletAddress", smartWalletAddress);
148+
console.log(
149+
"balance before",
150+
await getWalletBalance({
151+
address: smartAccount.address,
152+
chain: chain,
153+
client,
154+
tokenAddress: tokenPaymaster.tokenAddress,
155+
}),
156+
);
50157
const tx = prepareTransaction({
51158
client,
52-
chain: base,
159+
chain,
53160
to: smartAccount.address,
54161
value: 0n,
55162
});
@@ -58,6 +165,15 @@ describe.runIf(process.env.TW_SECRET_KEY).skip.sequential(
58165
account: smartAccount,
59166
});
60167
expect(receipt.transactionHash).toBeDefined();
168+
console.log(
169+
"balance after",
170+
await getWalletBalance({
171+
address: smartAccount.address,
172+
chain: chain,
173+
client,
174+
tokenAddress: tokenPaymaster.tokenAddress,
175+
}),
176+
);
61177
});
62178
},
63179
);

0 commit comments

Comments
 (0)