Skip to content

Commit

Permalink
[SDK] Feature: Adds deploySmartAccount and re-adds 1271 signatures (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
gregfromstl authored Jan 7, 2025
1 parent 66f1337 commit b058f68
Show file tree
Hide file tree
Showing 15 changed files with 2,942 additions and 4,317 deletions.
16 changes: 16 additions & 0 deletions .changeset/polite-trains-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"thirdweb": minor
---

Feature: Adds `deploySmartAccount` function to force the deployment of a smart account.

```ts
const account = await deploySmartAccount({
smartAccount,
chain,
client,
accountContract,
});
```

Fix: Uses 1271 signatures if the smart account is already deployed.
21 changes: 12 additions & 9 deletions packages/thirdweb/src/auth/verify-hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,7 @@ export async function verifyHash({
try {
const result = await eth_call(rpcRequest, verificationData);
return hexToBool(result);
} catch (err) {
console.error("Error verifying ERC-6492 signature", err);
} catch {
// Some chains do not support the eth_call simulation and will fail, so we fall back to regular EIP1271 validation
const validEip1271 = await verifyEip1271Signature({
hash,
Expand All @@ -154,7 +153,7 @@ export async function verifyHash({
}

const EIP_1271_MAGIC_VALUE = "0x1626ba7e";
async function verifyEip1271Signature({
export async function verifyEip1271Signature({
hash,
signature,
contract,
Expand All @@ -163,10 +162,14 @@ async function verifyEip1271Signature({
signature: Hex;
contract: ThirdwebContract;
}): Promise<boolean> {
const result = await isValidSignature({
hash,
signature,
contract,
});
return result === EIP_1271_MAGIC_VALUE;
try {
const result = await isValidSignature({
hash,
signature,
contract,
});
return result === EIP_1271_MAGIC_VALUE;
} catch {
return false;
}
}
2 changes: 2 additions & 0 deletions packages/thirdweb/src/exports/thirdweb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,5 @@ export {
type VerifyTypedDataParams,
verifyTypedData,
} from "../auth/verify-typed-data.js";

export { deploySmartAccount } from "../wallets/smart/lib/signing.js";
2 changes: 2 additions & 0 deletions packages/thirdweb/src/exports/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,5 @@ export * as EIP1193 from "../adapters/eip1193/index.js";
export { injectedProvider } from "../wallets/injected/mipdStore.js";

export type { ConnectionManager } from "../wallets/manager/index.js";

export { deploySmartAccount } from "../wallets/smart/lib/signing.js";
9 changes: 5 additions & 4 deletions packages/thirdweb/src/utils/abi/decodeError.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type Abi, AbiError } from "ox";
import type * as ox__Abi from "ox/Abi";
import * as ox__AbiError from "ox/AbiError";
import { resolveContractAbi } from "../../contract/actions/resolve-abi.js";
import type { ThirdwebContract } from "../../contract/contract.js";
import type { Hex } from "../encoding/hex.js";
Expand All @@ -17,7 +18,7 @@ import type { Hex } from "../encoding/hex.js";
*
* @utils
*/
export async function decodeError<abi extends Abi.Abi>(options: {
export async function decodeError<abi extends ox__Abi.Abi>(options: {
contract: ThirdwebContract<abi>;
data: Hex;
}) {
Expand All @@ -31,6 +32,6 @@ export async function decodeError<abi extends Abi.Abi>(options: {
`No ABI found for contract ${contract.address} on chain ${contract.chain.id}`,
);
}
const abiError = AbiError.fromAbi(abi, data) as AbiError.AbiError;
return AbiError.decode(abiError, data);
const abiError = ox__AbiError.fromAbi(abi, data) as ox__AbiError.AbiError;
return ox__AbiError.decode(abiError, data);
}
12 changes: 7 additions & 5 deletions packages/thirdweb/src/utils/abi/decodeFunctionData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { type Abi, AbiFunction, type Hex } from "ox";
import type * as ox__Abi from "ox/Abi";
import * as ox__AbiFunction from "ox/AbiFunction";
import type * as ox__Hex from "ox/Hex";
import { resolveContractAbi } from "../../contract/actions/resolve-abi.js";
import type { ThirdwebContract } from "../../contract/contract.js";

Expand All @@ -16,9 +18,9 @@ import type { ThirdwebContract } from "../../contract/contract.js";
*
* @utils
*/
export async function decodeFunctionData<abi extends Abi.Abi>(options: {
export async function decodeFunctionData<abi extends ox__Abi.Abi>(options: {
contract: ThirdwebContract<abi>;
data: Hex.Hex;
data: ox__Hex.Hex;
}) {
const { contract, data } = options;
let abi = contract?.abi;
Expand All @@ -30,6 +32,6 @@ export async function decodeFunctionData<abi extends Abi.Abi>(options: {
`No ABI found for contract ${contract.address} on chain ${contract.chain.id}`,
);
}
const abiFunction = AbiFunction.fromAbi(abi, data);
return AbiFunction.decodeData(abiFunction, data);
const abiFunction = ox__AbiFunction.fromAbi(abi, data);
return ox__AbiFunction.decodeData(abiFunction, data);
}
12 changes: 7 additions & 5 deletions packages/thirdweb/src/utils/abi/decodeFunctionResult.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { type Abi, AbiFunction, type Hex } from "ox";
import type * as ox__Abi from "ox/Abi";
import * as ox__AbiFunction from "ox/AbiFunction";
import type * as ox__Hex from "ox/Hex";
import { resolveContractAbi } from "../../contract/actions/resolve-abi.js";
import type { ThirdwebContract } from "../../contract/contract.js";

Expand All @@ -16,9 +18,9 @@ import type { ThirdwebContract } from "../../contract/contract.js";
*
* @utils
*/
export async function decodeFunctionResult<abi extends Abi.Abi>(options: {
export async function decodeFunctionResult<abi extends ox__Abi.Abi>(options: {
contract: ThirdwebContract<abi>;
data: Hex.Hex;
data: ox__Hex.Hex;
}) {
const { contract, ...rest } = options;
let abi = contract?.abi;
Expand All @@ -30,6 +32,6 @@ export async function decodeFunctionResult<abi extends Abi.Abi>(options: {
`No ABI found for contract ${contract.address} on chain ${contract.chain.id}`,
);
}
const abiFunction = AbiFunction.fromAbi(abi, rest.data);
return AbiFunction.decodeResult(abiFunction, rest.data);
const abiFunction = ox__AbiFunction.fromAbi(abi, rest.data);
return ox__AbiFunction.decodeResult(abiFunction, rest.data);
}
2 changes: 1 addition & 1 deletion packages/thirdweb/src/utils/hashing/hashMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bytes as ox__Bytes } from "ox";
import * as ox__Bytes from "ox/Bytes";
import type { Hex } from "../encoding/hex.js";
import { stringToBytes, toBytes } from "../encoding/to-bytes.js";
import type { SignableMessage } from "../types.js";
Expand Down
16 changes: 16 additions & 0 deletions packages/thirdweb/src/wallets/create-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,22 @@ import { createWalletEmitter } from "./wallet-emitter.js";
*
* [View Coinbase wallet creation options](https://portal.thirdweb.com/references/typescript/v5/CoinbaseWalletCreationOptions)
*
* ## Connecting with a smart wallet
*
* ```ts
* import { createWallet } from "thirdweb/wallets";
*
* const wallet = createWallet("smart", {
* chain: sepolia,
* sponsorGas: true,
* });
*
* const account = await wallet.connect({
* client,
* personalAccount, // pass the admin account
* });
* ```
*
* @wallet
*/
export function createWallet<const ID extends WalletId>(
Expand Down
39 changes: 20 additions & 19 deletions packages/thirdweb/src/wallets/smart/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ async function createSmartAccount(
}
}

const { accountContract } = options;
let accountContract = options.accountContract;
const account: Account = {
address: getAddress(accountContract.address),
async sendTransaction(transaction: SendTransactionOption) {
Expand All @@ -237,21 +237,17 @@ async function createSmartAccount(
paymasterOverride = options.overrides?.paymaster;
}

const accountContractForTransaction = (() => {
// If this transaction is for a different chain than the initial one, get the account contract for that chain
if (transaction.chainId !== accountContract.chain.id) {
return getContract({
address: account.address,
chain: getCachedChain(transaction.chainId),
client: options.client,
});
}
// Default to the existing account contract
return accountContract;
})();
// If this transaction is for a different chain than the initial one, get the account contract for that chain
if (transaction.chainId !== accountContract.chain.id) {
accountContract = getContract({
address: account.address,
chain: getCachedChain(transaction.chainId),
client: options.client,
});
}

const executeTx = prepareExecute({
accountContract: accountContractForTransaction,
accountContract: accountContract,
transaction,
executeOverride: options.overrides?.execute,
});
Expand All @@ -260,6 +256,7 @@ async function createSmartAccount(
options: {
...options,
chain: getCachedChain(transaction.chainId),
accountContract,
overrides: {
...options.overrides,
paymaster: paymasterOverride,
Expand All @@ -275,7 +272,11 @@ async function createSmartAccount(
});
return _sendUserOp({
executeTx,
options,
options: {
...options,
chain: getCachedChain(transactions[0]?.chainId ?? options.chain.id),
accountContract,
},
});
},
async signMessage({ message }: { message: SignableMessage }) {
Expand All @@ -288,8 +289,8 @@ async function createSmartAccount(
});
}

const { deployAndSignMessage } = await import("./lib/signing.js");
return deployAndSignMessage({
const { smartAccountSignMessage } = await import("./lib/signing.js");
return smartAccountSignMessage({
accountContract,
factoryContract: options.factoryContract,
options,
Expand All @@ -309,8 +310,8 @@ async function createSmartAccount(
});
}

const { deployAndSignTypedData } = await import("./lib/signing.js");
return deployAndSignTypedData({
const { smartAccountSignTypedData } = await import("./lib/signing.js");
return smartAccountSignTypedData({
accountContract,
factoryContract: options.factoryContract,
options,
Expand Down
Loading

0 comments on commit b058f68

Please sign in to comment.