5.2.11 • Published 2 days ago

@zerodev/sdk v5.2.11

Weekly downloads
-
License
MIT
Repository
-
Last release
2 days ago

ZeroDev SDK

SDK for ZeroDev, based on Kernel.

Getting started

Follow the instructions below to install the packages.

via yarn

yarn add @alchemy/aa-core @alchemy/aa-ethers @zerodevapp/sdk@alpha

via npm

npm i -s @alchemy/aa-core @alchemy/aa-ethers @zerodev/sdk@alpha

Example Usage to Interact with Kernel Accounts

Basic Usage

import { ECDSAValidator } from "@zerodev/sdk@alpha";
import { PrivateKeySigner } from "@alchemy/aa-core";

// 1. define the EOA owner of the Smart Account
// This is just one exapmle of how to interact with EOAs, feel free to use any other interface
const owner = PrivateKeySigner.privateKeyToAccountSigner(PRIVATE_KEY);

// 2. Create a ZeroDev Provider
let ecdsaProvider = await ECDSAProvider.init({
  projectId, // zeroDev projectId
  owner,
  // Optional: pass the paymasterConfig to use the verifying paymaster
  // opts: {
  //     paymasterConfig: {
  //         policy: "VERIFYING_PAYMASTER"
  //     }
  // }
});

// 3. send a UserOperation
const { hash } = await ecdsaProvider.sendUserOperation({
  target: "0xTargetAddress",
  data: "0xcallData",
  value: 0n, // value: bigint or undefined
});

// 4. Wait for UserOp
const tx = await ecdsaProvider.waitForUserOperationTransaction(
  result.hash as Hex
);

Batch Transactions

const { hash } = await ecdsaProvider.sendUserOperation([
  {
    target: "0xTargetAddress1",
    data: "0xcallData1",
    value: 0n, // value: bigint or undefined
  },
  {
    target: "0xTargetAddress2",
    data: "0xcallData2",
    value: 0n, // value: bigint or undefined
  },
]);

Optional params for ValidatorProvider:

OptionUsageTypeDefault
bundlerProviderBundler Provider"ALCHEMY", "STACKUP", "PIMLICO""STACKUP"
usePaymasterUse paymaster to send userOpsbooleantrue
opts:paymasterConfig:paymasterProviderPaymaster Provider"ALCHEMY", "STACKUP", "PIMLICO""STACKUP"
opts:paymasterConfig:onlySendSponsoredTransactionOnly send sponsored transaction and revert if somehow paymaster failsbooleanfalse
opts:paymasterConfig:policyPaymaster policy"TOKEN_PAYMASTER", "VERIFYING_PAYMASTER""VERIFYING_PAYMASTER"
opts:paymasterConfig:gasTokenERC20 token to use for gas fees in case of "TOKEN_PAYMASTER""USDC", "PEPE", "TEST_ERC20"(Required)
opts:providerConfig:rpcUrlCustom RPC URL for the bundler providerstring"https://v0-6-meta-bundler.onrender.com"
opts:providerConfig:opts:txMaxRetriesThe maximum number of times to try fetching a transaction receipt before giving upnumber5
opts:providerConfig:opts:txRetryIntervalMsThe interval in milliseconds to wait between retries while waiting for tx receiptsnumber2000
opts:providerConfig:opts:minPriorityFeePerBidused when computing the fees for a user operationbigint100_000_000n, Chain-wise defaults
opts:providerConfig:opts:sendTxMaxRetriesThe maximum number of times to try sending a transaction before giving upnumber3
opts:providerConfig:opts:sendTxRetryIntervalMsThe interval in milliseconds to wait between retries while sending a transactionnumber180000
opts:accountConfig:indexIndex variable to be used alongwith with owner address and validator data while calculating counterfactual addressnumber1000
TODO include other options

Pay gas in ERC20

ZeroDev currently supports:

  • USDC
  • PEPE (mainnet only)
  • DAI (upcoming)

Just pass the paymasterConfig to createZeroDevProvider function while creating the provider.

let ecdsaProvider = await ECDSAProvider.init({
  projectId, // zeroDev projectId
  owner,
  opts: {
    paymasterConfig: {
      policy: "TOKEN_PAYMASTER",
      gasToken: "TEST_ERC20",
    },
  },
});

Change Kernel Account Owner in ECDSAValidator

// 1. Create a ECDSAValidatorProvider
const ecdsaProvider = await ECDSAProvider.init({
    projectId: "c73037ef-8c0b-48be-a581-1f3d161151d3",
    owner,
});

// 2. Change the owner of the Kernel Account
const { hash } = await ecdsaProvider.changeOwner(<NEW_OWNER_ADDRESS>);

Via ethers Signer

import { Wallet } from "@ethersproject/wallet";
import {
  ZeroDevEthersProvider,
  convertEthersSignerToAccountSigner,
} from "@zerodev/sdk@alpha";

// 1. Create an ethers Wallet
const owner = Wallet.fromMnemonic(OWNER_MNEMONIC);

// 2. Create a ZeroDev ZeroDevEthersProvider passing the ethers Wallet as the signer
const provider = await ZeroDevEthersProvider.init("ECDSA", {
  projectId, // zeroDev projectId
  owner: convertEthersSignerToAccountSigner(owner),
  opts: {
    paymasterConfig: {
      policy: "VERIFYING_PAYMASTER",
    },
  },
});

// 3. Get the AccountSigner adapter of ethers signer
const signer = provider.getAccountSigner();

// 4. send a UserOperation
const { hash } = await signer.sendUserOperation({
  target: "0xTargetAddress",
  data: "0xcallData",
  value: 0n, // value: bigint or undefined
});

Via viem using custom transport which supports EIP-1193 providers

import { createWalletClient, custom } from "viem";
import { polygonMumbai } from "viem/chains";
import {
  ECDSAProvider,
  convertWalletClientToAccountSigner,
} from "@zerodev/sdk@alpha";

// 1. Create a Viem Wallet Client using the custom transport
const client = createWalletClient({
  chain: polygonMumbai,
  transport: custom(window.ethereum),
});

// 2. Create a ZeroDev ECDSAProvider passing the Viem Wallet Client as the signer
let ecdsaProvider = await ECDSAProvider.init({
  projectId, // zeroDev projectId
  owner: convertWalletClientToAccountSigner(client),
});

// 3. send a UserOperation
const { hash } = await ecdsaProvider.sendUserOperation({
  target: "0xTargetAddress",
  data: "0xcallData",
  value: 0n, // value: bigint or undefined
});

Using Magic

import { ECDSAProvider, getRPCProviderOwner } from "@zerodev/sdk@alpha";
import { Magic } from "magic-sdk";

const magic = new Magic("MAGIC_API_KEY", {
  // magic config...
});

let ecdsaProvider = await ECDSAProvider.init({
  projectId, // zeroDev projectId
  owner: getRPCProviderOwner(magic.rpcProvider),
});

Using Web3Auth

import { ECDSAProvider, getRPCProviderOwner } from "@zerodev/sdk@alpha";
import { Web3Auth } from "@web3auth/modal";

const web3auth = new Web3Auth({
  // web3auth config...
});

await web3auth.initModal();

web3auth.connect();

let ecdsaProvider = await ECDSAProvider.init({
  projectId, // zeroDev projectId
  owner: getRPCProviderOwner(web3auth.provider),
});

Using validator plugins

Kill Switch Validator

A designated guardian can "turn off" the account and set a new owner.

import { constants } from "@zerodev/sdk@alpha";
// 1. Get the default ecdsa validator provider
const ecdsaProvider = await ECDSAProvider.init({
  projectId, // zeroDev projectId
  owner,
});

// 2. Deploy the Kernel account if not already by sending an empty transaction
let result = await ecdsaProvider.sendUserOperation({
  target: "0xADDRESS",
  data: "0x",
});
await ecdsaProvider.waitForUserOperationTransaction(result.hash as Hex);

// 3. Initialize required variables
const accountAddress = await ecdsaProvider.getAccount().getAddress();
const selector = getFunctionSelector("toggleKillSwitch()");

// 4. Initialize KillSwitch Validator Provider
const blockerKillSwitchProvider = await KillSwitchProvider.init({
  projectId, // zeroDev projectId
  owner,
  guardian, // Guardian signer
  delaySeconds: 1000, // Delay in seconds
  opts: {
    accountConfig: {
      accountAddress,
    },
    validatorConfig: {
      mode: ValidatorMode.plugin,
      executor: constants.KILL_SWITCH_ACTION, // Address of the executor contract
      selector, // Function selector in the executor contract to toggleKillSwitch()
    },
  },
});

// 5. Get enable signature from default ECDSA validator provider and set it in KillSwitch Validator Provider
const enableSig = await ecdsaProvider
  .getValidator()
  .approveExecutor(
    accountAddress,
    selector,
    constants.KILL_SWITCH_ACTION,
    0,
    0,
    blockerKillSwitchProvider.getValidator()
  );

blockerKillSwitchProvider.getValidator().setEnableSignature(enableSig);

// 6. Send the transaction to turn on the KillSwitch
result = await blockerKillSwitchProvider.sendUserOperation({
  target: accountAddress,
  data: selector,
});

await blockerKillSwitchProvider.waitForUserOperationTransaction(
  result.hash as Hex
);

// 7. Get KillSwitch validator provider instance with SUDO mode
const sudoModeKillSwitchProvider = await KillSwitchProvider.init({
  projectId, // zeroDev projectId
  owner,
  guardian,
  delaySeconds: 0,
  opts: {
    accountConfig: {
      accountAddress,
    },
    validatorConfig: {
      mode: ValidatorMode.sudo,
      executor: KILL_SWITCH_ACTION,
      selector,
    },
  },
});

// 8. Send transaction to change the owner address
const changeOwnerdata = await ecdsaProvider.getEncodedEnableData(
  "0xNEW_OWNER_ADDRESS"
);
let result = await sudoModeKillSwitchProvider.sendUserOperation({
  target: accountAddress,
  data: changeOwnerdata,
});

await sudoModeKillSwitchProvider.waitForUserOperationTransaction(
  result.hash as Hex
);

ERC165 Session Key Validator

// 1. Get the default ecdsa validator provider
const ecdsaProvider = await ECDSAProvider.init({
  projectId, // zeroDev projectId
  owner,
});

// 2. Deploy the Kernel account if not already by sending an empty transaction
let result = await ecdsaProvider.sendUserOperation({
  target: "0xADDRESS",
  data: "0x",
});
await ecdsaProvider.waitForUserOperationTransaction(result.hash as Hex);

// 3. Initialize required variables
const accountAddress = await ecdsaProvider.getAccount().getAddress();
const selector = getFunctionSelector(
  "transferERC721Action(address, uint256, address)"
);

// 4. Initialize ERC165SessionKey Validator Provider
const erc165SessionKeyProvider = await ERC165SessionKeyProvider.init({
  projectId, // ZeroDev projectId
  owner,
  sessionKey, // Session Key signer
  sessionKeyData: {
    selector, // Function selector in the executor contract to execute
    erc165InterfaceId: "0x80ac58cd", // Supported interfaceId of the contract the executor calls
    validAfter: 0,
    validUntil: 0,
    addressOffset: 16, // Address offest of the contract called by the executor in the calldata
  },
  opts: {
    accountConfig: {
      accountAddress,
    },
    validatorConfig: {
      mode: ValidatorMode.plugin,
      executor: constants.TOKEN_ACTION, // Address of the executor contract
      selector, // Function selector in the executor contract to execute
    },
  },
});

// 5. Get enable signature from default ECDSA validator provider and set it in ERC165SessionKey Validator Provider
const enableSig = await ecdsaProvider
  .getValidator()
  .approveExecutor(
    accountAddress,
    selector,
    constants.TOKEN_ACTION,
    0,
    0,
    erc165SessionKeyProvider.getValidator()
  );

erc165SessionKeyProvider.getValidator().setEnableSignature(enableSig);

// 6. Send the transaction
const { hash } = await erc165SessionKeyProvider.sendUserOperation({
  target: accountAddress,
  data: encodeFunctionData({
    abi: TokenActionsAbi,
    functionName: "transferERC721Action",
    args: ["TOKEN_ADDRESS", "TOKEN_ID", "RECIPIENT_ADDRESS"],
  }),
});

Components

Core Components

The primary interfaces are the ZeroDevProvider, KernelSmartContractAccount and KernelBaseValidator

The ZeroDevProvider is an ERC-1193 compliant Provider built on top of Alchemy's SmartAccountProvider

  1. sendUserOperation -- this takes in target, callData, and an optional value which then constructs a UserOperation (UO), sends it, and returns the hash of the UO. It handles estimating gas, fetching fee data, (optionally) requesting paymasterAndData, and lastly signing. This is done via a middleware stack that runs in a specific order. The middleware order is getDummyPaymasterData => estimateGas => getFeeData => getPaymasterAndData. The paymaster fields are set to 0x by default. They can be changed using provider.withPaymasterMiddleware.
  2. sendTransaction -- this takes in a traditional Transaction Request object which then gets converted into a UO. Currently, the only data being used from the Transaction Request object is from, to, data and value. Support for other fields is coming soon.

KernelSmartContractAccount is Kernel's implementation of BaseSmartContractAccount. 6 main methods are implemented

  1. getDummySignature -- this method should return a signature that will not revert during validation. It does not have to pass validation, just not cause the contract to revert. This is required for gas estimation so that the gas estimate are accurate.
  2. encodeExecute -- this method should return the abi encoded function data for a call to your contract's execute method
  3. encodeExecuteDelegate -- this method should return the abi encoded function data for a delegate call to your contract's execute method
  4. signMessage -- this is used to sign UO Hashes
  5. signWithEip6492 -- this should return an ERC-191 and EIP-6492 compliant message used to personal_sign
  6. getAccountInitCode -- this should return the init code that will be used to create an account if one does not exist. Usually this is the concatenation of the account's factory address and the abi encoded function data of the account factory's createAccount method.

The KernelBaseValidator is a plugin that modify how transactions are validated. It allows for extension and implementation of arbitrary validation logic. It implements 3 main methods:

  1. getAddress -- this returns the address of the validator
  2. getOwner -- this returns the eligible signer's address for the active smart wallet
  3. getSignature -- this method signs the userop hash using signer object and then concats additional params based on validator mode.

Contributing

  1. clone the repo
  2. run yarn
  3. Make changes to packages

Adding new custom validator plugin

  1. Create a new validator class that extends KernelBaseValidator similar to ECDSAValidator.

  2. Make sure to pass the validatorAddress of your validator to the KernelBaseValidator base class.

  3. Create a new validator provider that extends ValidatorProvider similar to ECDSAValidatorProvider.

  4. Use the newly created validator provider as per above examples.

KernelBaseValidator methods to be implemented in your validator class

  • signer() -- this method should return the signer as per your validator's implementation. For example, for Multi-Signature validator, this method should return one of the owner signer which is connected to the multisig wallet contract and currently using the DAPP.
  • getOwner() -- this method should return the address of the signer. For example, for Multi-Signature validator, this method should return the address of the signer which is connected to the multisig wallet contract and currently using the DAPP.
  • getEnableData() -- this method should return the bytes data for the enable method of your validator contract. For example, in ECDSA validator, this method returns owner address as bytes data. This method is used to enable the validator for the first time while creating the account wallet.
  • encodeEnable(enableData: Hex) -- this method should return the abi encoded function data for the enable method of your validator contract. For example, in ECDSA validator, this method returns the abi encoded function data for the enable method with owner address as bytes param.
  • encodeDisable(disableData: Hex) -- this method should return the abi encoded function data for the disable method of your validator contract. For example, in ECDSA validator, this method returns the abi encoded function data for the disable method with empty bytes param since ECDSA Validator doesn't require any param.
  • signMessage(message: Uint8Array | string | Hex) -- this method should return the signature of the message using the connected signer.
  • signUserOp(userOp: UserOperationRequest) -- this method should return the signature of the userOp hash using the connected signer.
5.2.12-alpha-1

2 days ago

5.2.12-alpha-2

2 days ago

5.2.12-alpha-0

6 days ago

5.2.11

9 days ago

5.2.10

13 days ago

5.2.9

14 days ago

5.2.8

15 days ago

4.7.7

15 days ago

5.2.7

15 days ago

5.2.6

19 days ago

5.2.5

21 days ago

5.2.4

21 days ago

5.2.3

22 days ago

5.2.2

23 days ago

5.2.1

23 days ago

5.2.0

27 days ago

5.2.1-alpha-10

27 days ago

5.2.1-alpha-9

28 days ago

5.2.1-alpha-7

29 days ago

5.2.1-alpha-8

29 days ago

5.2.1-alpha-5

1 month ago

5.2.1-alpha-4

1 month ago

5.2.1-alpha-6

1 month ago

5.2.1-alpha-3

1 month ago

5.2.1-alpha-1

1 month ago

5.2.1-alpha-2

1 month ago

5.2.0-alpha-3

1 month ago

5.2.0-alpha-4

1 month ago

5.2.1-alpha-0

1 month ago

5.1.18

1 month ago

5.1.17

1 month ago

5.2.0-alpha-2

1 month ago

4.7.6

1 month ago

4.7.5

1 month ago

5.1.16

1 month ago

5.1.15

1 month ago

5.1.14

1 month ago

5.2.0-alpha-1

2 months ago

5.2.0-alpha-0

2 months ago

5.1.13

2 months ago

5.0.0-alpha-0

2 months ago

5.1.12

2 months ago

4.7.4

2 months ago

4.7.2

2 months ago

4.7.3

2 months ago

5.1.9

2 months ago

5.1.11

2 months ago

5.1.10

2 months ago

5.1.8

2 months ago

4.7.1

2 months ago

5.1.7

2 months ago

4.7.0

2 months ago

4.6.11

2 months ago

5.1.6

3 months ago

5.1.5

3 months ago

4.6.10

3 months ago

5.1.4

3 months ago

5.1.3

3 months ago

5.1.2

3 months ago

5.1.1

3 months ago

5.1.0

3 months ago

4.6.9

3 months ago

4.6.8

3 months ago

4.6.7

3 months ago

4.6.6

3 months ago

4.6.3

3 months ago

4.6.5

3 months ago

4.6.4

3 months ago

5.1.0-beta.0

3 months ago

5.1.0-beta.1

3 months ago

5.0.9

3 months ago

5.0.8

3 months ago

5.0.7

3 months ago

5.0.6

3 months ago

5.0.5

3 months ago

5.0.4

3 months ago

5.0.3

3 months ago

5.0.2

3 months ago

4.6.2

3 months ago

5.0.1

3 months ago

4.6.1

4 months ago

5.0.0

4 months ago

5.0.0-beta.0

4 months ago

4.6.0

4 months ago

4.5.5

4 months ago

4.5.4

4 months ago

4.5.3

4 months ago

4.5.2-beta.0

5 months ago

4.5.2

5 months ago

4.5.1

5 months ago

4.5.0

5 months ago

4.4.3

5 months ago

4.4.2

5 months ago

4.4.1

5 months ago

4.4.0

5 months ago

4.3.4

6 months ago

4.3.3

6 months ago

4.3.2

6 months ago

4.3.1

6 months ago

4.3.0

6 months ago

4.2.3

6 months ago

4.2.2

6 months ago

4.2.1

6 months ago

4.2.0

6 months ago

4.1.5

6 months ago

4.1.4

6 months ago

4.1.3

6 months ago

4.1.2

6 months ago

4.1.1

6 months ago

4.1.0

6 months ago

4.0.34

6 months ago

4.0.33

6 months ago

4.0.32

7 months ago

4.0.31

7 months ago

4.0.30

7 months ago

4.0.29

7 months ago

4.0.28

7 months ago

4.0.27

7 months ago

4.0.26

7 months ago

4.0.25

7 months ago

4.0.24

7 months ago

4.0.23

7 months ago

4.0.22

7 months ago

4.0.21

7 months ago

4.0.20

8 months ago

4.0.19

8 months ago

4.0.18

8 months ago

4.0.17

8 months ago

4.0.16

8 months ago

4.0.15

8 months ago

4.0.14

8 months ago

4.0.13

8 months ago

4.0.12

8 months ago

4.0.11

8 months ago

4.0.10

8 months ago

4.0.9

9 months ago

4.0.8

9 months ago

4.0.7

9 months ago

4.0.6

9 months ago

4.0.5

9 months ago

4.0.4

9 months ago

4.0.3

9 months ago

4.0.2

9 months ago

4.0.1

9 months ago

4.0.0

9 months ago

4.0.2-alpha.26

9 months ago

4.0.2-passkey.1

9 months ago

4.0.2-passkey.0

9 months ago

4.0.2-alpha.25

9 months ago

4.0.2-alpha.24

9 months ago

4.0.2-alpha.23

9 months ago