Skip to content

Commit fc2cf41

Browse files
working version
1 parent 0eee1ff commit fc2cf41

File tree

8 files changed

+203
-136
lines changed

8 files changed

+203
-136
lines changed

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

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,7 @@ import type {
3232
SendTransactionOption,
3333
Wallet,
3434
} from "../interfaces/wallet.js";
35-
import type {
36-
CreateWalletArgs,
37-
WalletConnectionOption,
38-
WalletId,
39-
} from "../wallet-types.js";
35+
import type { WalletId } from "../wallet-types.js";
4036
import {
4137
broadcastZkTransaction,
4238
bundleUserOp,
@@ -91,8 +87,8 @@ const smartWalletToPersonalAccountMap = new WeakMap<Wallet<"smart">, Account>();
9187
*/
9288
export async function connectSmartWallet(
9389
wallet: Wallet<"smart">,
94-
connectionOptions: WalletConnectionOption<"smart">,
95-
creationOptions: CreateWalletArgs<"smart">[1],
90+
connectionOptions: SmartWalletConnectionOptions,
91+
creationOptions: SmartWalletOptions,
9692
): Promise<[Account, Chain]> {
9793
const { personalAccount, client, chain: connectChain } = connectionOptions;
9894

@@ -116,7 +112,6 @@ export async function connectSmartWallet(
116112
entrypointAddress,
117113
};
118114
}
119-
console.log("entrypointAddress", entrypointAddress);
120115
}
121116

122117
const factoryAddress =
@@ -159,8 +154,6 @@ export async function connectSmartWallet(
159154
);
160155
});
161156

162-
console.log("accountAddress", accountAddress);
163-
164157
const accountContract = getContract({
165158
client,
166159
address: accountAddress,
@@ -331,7 +324,7 @@ async function createSmartAccount(
331324
message: { message: wrappedMessageHash },
332325
});
333326
if (isModularFactory) {
334-
// add validator address
327+
// TODO (msa) - override for signatures to add validator address
335328
sig = encodePacked(
336329
["address", "bytes"],
337330
["0x6DF8ea6FF6Ca55f367CDA45510CA40dC78993DEC", sig],
@@ -341,8 +334,6 @@ async function createSmartAccount(
341334
sig = await options.personalAccount.signMessage({ message });
342335
}
343336

344-
console.log("sig", sig);
345-
346337
const isValid = await verifyContractWalletSignature({
347338
address: accountContract.address,
348339
chain: accountContract.chain,

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export async function predictAddress(args: {
6666
factoryContract: ThirdwebContract;
6767
predictAddressOverride?: (
6868
factoryContract: ThirdwebContract,
69+
admin?: string,
6970
) => Promise<string>;
7071
adminAddress: string;
7172
accountSalt?: string;
@@ -79,7 +80,7 @@ export async function predictAddress(args: {
7980
accountAddress,
8081
} = args;
8182
if (predictAddress) {
82-
return predictAddress(factoryContract);
83+
return predictAddress(factoryContract, adminAddress);
8384
}
8485
if (accountAddress) {
8586
return accountAddress;
@@ -109,6 +110,7 @@ export function prepareCreateAccount(args: {
109110
accountSalt?: string;
110111
createAccountOverride?: (
111112
factoryContract: ThirdwebContract,
113+
admin?: string,
112114
) => PreparedTransaction;
113115
}): PreparedTransaction {
114116
const {
@@ -118,7 +120,7 @@ export function prepareCreateAccount(args: {
118120
accountSalt,
119121
} = args;
120122
if (createAccount) {
121-
return createAccount(factoryContract);
123+
return createAccount(factoryContract, adminAddress);
122124
}
123125
const saltHex =
124126
accountSalt && isHex(accountSalt)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getAddress } from "../../../utils/address.js";
33
import { getThirdwebDomains } from "../../../utils/domains.js";
44

55
// dev only
6-
export const DEBUG = true;
6+
export const DEBUG = false;
77

88
export const DUMMY_SIGNATURE =
99
"0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,6 @@ async function getAccountNonce(options: {
657657
* @example
658658
* ```ts
659659
* import { createAndSignUserOp } from "thirdweb/wallets/smart";
660-
import { keccak256 } from "../../../utils/hashing/keccak256.js";
661660
*
662661
* const userOp = await createAndSignUserOp({
663662
* client,
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { AbiParameters, Hash, Hex } from "ox";
2+
import { ZERO_ADDRESS } from "../../../constants/addresses.js";
3+
import { getContract } from "../../../contract/contract.js";
4+
import { getNonce } from "../../../extensions/erc4337/__generated__/IEntryPoint/read/getNonce.js";
5+
import { encodeSingleInitMSA } from "../../../extensions/erc7579/__generated__/Bootstrap/write/singleInitMSA.js";
6+
import { execute } from "../../../extensions/erc7579/__generated__/IERC7579Account/write/execute.js";
7+
import { prepareContractCall } from "../../../transaction/prepare-contract-call.js";
8+
import { readContract } from "../../../transaction/read-contract.js";
9+
import { getAddress } from "../../../utils/address.js";
10+
import { toHex } from "../../../utils/encoding/hex.js";
11+
import { ENTRYPOINT_ADDRESS_v0_7 } from "../lib/constants.js";
12+
import { generateRandomUint192 } from "../lib/utils.js";
13+
import type { SmartWalletOptions } from "../types.js";
14+
15+
export type ModuleType = "validator" | "executor" | "fallback" | "hook";
16+
export type Module = {
17+
address: string;
18+
installData?: string;
19+
uninstallData?: string;
20+
type: ModuleType;
21+
};
22+
23+
export type Erc7579Options = SmartWalletOptions & {
24+
defaultModules?: Module[];
25+
};
26+
27+
// TODO (msa) - actual addresses here instead of test ones
28+
const REFERENCE_BOOTSTRAP_ADDRESS =
29+
"0xedd4503de72bac321dfeb65f1373d2def17403fc";
30+
const REFERENCE_FACTORY_ADDRESS = "0xC7c2a0aC7334f84bAe0EB1c4e42526FB6ea2e661"; //"0xa951A1179bA8bd08b8140aB9dc7910AF08AE7181";
31+
const REFERENCE_VALIDATOR_ADDRESS =
32+
"0x6DF8ea6FF6Ca55f367CDA45510CA40dC78993DEC";
33+
34+
export function erc7579Config(options: Erc7579Options): SmartWalletOptions {
35+
return {
36+
...options,
37+
factoryAddress: options.factoryAddress || REFERENCE_FACTORY_ADDRESS,
38+
overrides: {
39+
entrypointAddress: ENTRYPOINT_ADDRESS_v0_7,
40+
createAccount(factoryContract, admin) {
41+
return prepareContractCall({
42+
contract: factoryContract,
43+
// TODO (msa) - adapt to our own 7579 factory
44+
method: "function createAccount(bytes32 salt, bytes initCode)",
45+
params: [
46+
Hash.keccak256(admin ? getAddress(admin) : ZERO_ADDRESS),
47+
AbiParameters.encode(
48+
[{ type: "address" }, { type: "bytes" }],
49+
[
50+
REFERENCE_BOOTSTRAP_ADDRESS, // bootstrap
51+
encodeSingleInitMSA({
52+
validator: REFERENCE_VALIDATOR_ADDRESS,
53+
data: "0x",
54+
}),
55+
],
56+
),
57+
],
58+
});
59+
},
60+
async predictAddress(factoryContract, admin) {
61+
return readContract({
62+
contract: factoryContract,
63+
method:
64+
"function getAddress(bytes32 salt, bytes initCode) returns (address)",
65+
// TODO (msa) - adapt to our own 7579 factory
66+
params: [
67+
Hash.keccak256(admin ? getAddress(admin) : ZERO_ADDRESS),
68+
AbiParameters.encode(
69+
[{ type: "address" }, { type: "bytes" }],
70+
[
71+
REFERENCE_BOOTSTRAP_ADDRESS, // bootstrap
72+
encodeSingleInitMSA({
73+
validator: REFERENCE_VALIDATOR_ADDRESS,
74+
data: "0x",
75+
}),
76+
],
77+
),
78+
],
79+
});
80+
},
81+
execute(accountContract, transaction) {
82+
return execute({
83+
contract: accountContract,
84+
async asyncParams() {
85+
return {
86+
mode: Hex.padRight("0x00", 32), // single execution
87+
executionCalldata: AbiParameters.encodePacked(
88+
["address", "uint256", "bytes"],
89+
[
90+
transaction.to || ZERO_ADDRESS,
91+
transaction.value || 0n,
92+
transaction.data || "0x",
93+
],
94+
),
95+
};
96+
},
97+
});
98+
},
99+
executeBatch(accountContract, transactions) {
100+
return execute({
101+
contract: accountContract,
102+
async asyncParams() {
103+
return {
104+
mode: Hex.padRight("0x01", 32), // batch execution
105+
executionCalldata: AbiParameters.encode(
106+
[
107+
{
108+
type: "tuple[]",
109+
components: [
110+
{ type: "address", name: "to" },
111+
{ type: "uint256", name: "value" },
112+
{ type: "bytes", name: "data" },
113+
],
114+
},
115+
],
116+
[
117+
transactions.map((t) => ({
118+
to: t.to || ZERO_ADDRESS,
119+
value: t.value || 0n,
120+
data: t.data || "0x",
121+
})),
122+
],
123+
),
124+
};
125+
},
126+
});
127+
},
128+
async getAccountNonce(accountContract) {
129+
const nonce = await getNonce({
130+
contract: getContract({
131+
address: ENTRYPOINT_ADDRESS_v0_7,
132+
chain: accountContract.chain,
133+
client: accountContract.client,
134+
}),
135+
key: generateRandomUint192(),
136+
sender: accountContract.address,
137+
});
138+
const withValidator = `${REFERENCE_VALIDATOR_ADDRESS}${toHex(nonce).slice(42)}`;
139+
return Hex.toBigInt(withValidator as Hex.Hex);
140+
},
141+
...options.overrides,
142+
},
143+
};
144+
}

0 commit comments

Comments
 (0)