fleet

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 12, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package fleet provides a slim client for acting as the regular signer on a Kernel V3.1 shared account that was already provisioned + installed by an admin service (e.g. DIMO accounts at POST /api/shared/account/email).

The admin handled all the on-chain setup: deployed the kernel, installed a weighted-ECDSA secondary validator with the admin's Turnkey EOA and the fleet's EOA as guardians (each at weight 100, threshold 100). By the time the fleet has the kernel address, the validator is already authorized for executeUserOp.

What this package does for the fleet:

  • SendCall: build, sign (EIP-191 personal-sign over userOpHash), and submit a plain regular-mode UserOp through a ZeroDev bundler + paymaster.
  • IsFleetInstalled: defensive probe — eth_getCode + isAllowedSelector read against the kernel. Useful for sanity-checking that the kernel handed to us by the admin really is set up the way we expect before we start sending UserOps.

It deliberately does NOT include the enable-mode install path (deploy + install + first action in one UserOp) — the admin owns that step, and every entry point removed from this package was specific to that flow. See zdexplore/scripts 10–12 for the install-from-admin proof-of-life and the accounts service for the production implementation.

Index

Constants

View Source
const ValidatorModeDefault byte = 0x00

Validator mode — byte 0 of the 24-byte Kernel V3 nonce key. We only ever submit DEFAULT-mode UserOps; ENABLE mode is exclusively the admin's concern.

View Source
const ValidatorTypeSecondary byte = 0x01

Validator type — byte 1 of the nonce key. Mirrors the type byte that prefixes a 21-byte ValidationId stored on chain. SECONDARY for a weighted-ECDSA validator.

Variables

View Source
var (
	EntryPoint07Address  = common.HexToAddress("0x0000000071727De22E5E9d8BAf0edAc6f37da032")
	WeightedEcdsaAddress = common.HexToAddress("0xeD89244160CfE273800B58b1B534031699dFeEEE")
)

Kernel V3.1 known addresses. Deterministic CREATE2 deployments — same on every chain ZeroDev supports — but verify with eth_getCode on the target chain before relying on this (Polygon Amoy notably lacks the weighted-ECDSA validator at the time of writing).

View Source
var ExecuteUserOpSelector = [4]byte{0xe9, 0xae, 0x5c, 0x53}

ExecuteUserOpSelector is the Kernel V3 selector that an EntryPoint v0.7 UserOp's callData targets when the kernel implements the executeUserOp optimization. IsFleetInstalled checks that the regular validator has been granted permission for this selector specifically.

Functions

func FullNonce

func FullNonce(key [24]byte, seq uint64) *big.Int

FullNonce composes the EntryPoint's 256-bit nonce from a 24-byte key and 8-byte sequence (as returned by EntryPoint.getNonce).

func IsFleetInstalled

func IsFleetInstalled(ctx context.Context, rpc types.RPCClient, kernel common.Address) (bool, error)

IsFleetInstalled returns true when (a) the kernel is deployed AND (b) the weighted-ECDSA validator is installed with selector permission for executeUserOp. Useful as a sanity check before sending the first UserOp against a kernel the admin claimed to provision — if either side returns false, something on the admin side didn't complete and a SendCall will fail.

The deployment check is folded in because isAllowedSelector reverts on a non-existent contract.

func NonceKey

func NonceKey(mode, validatorType byte, identifier common.Address, customKey uint16) [24]byte

NonceKey builds the 24-byte (uint192) nonce key the kernel uses to route a UserOp to a specific validator. Layout, matching the SDK's toKernelPluginManager.getNonceKey for EntryPoint v0.7:

byte 0      : validator mode  (0x00 = default; ENABLE is admin-only
              and not produced here)
byte 1      : validator type  (0x01 = secondary)
bytes 2..21 : validator identifier (right-padded to 20 bytes — for
              weighted-ECDSA, the validator contract address as-is)
bytes 22-23 : caller-chosen 16-bit custom key (for sequence isolation)

The full EntryPoint nonce is then (key << 64) | seq, where seq comes from EntryPoint.getNonce(account, key).

func NonceKeyAsUint192

func NonceKeyAsUint192(key [24]byte) *big.Int

NonceKeyAsUint192 converts the 24-byte key into the *big.Int the EntryPoint.getNonce(address, uint192) call accepts.

func NonceKeyDefaultModeForWeightedEcdsa

func NonceKeyDefaultModeForWeightedEcdsa(customKey uint16) [24]byte

NonceKeyDefaultModeForWeightedEcdsa is shorthand for the regular-mode nonce key targeting the weighted-ECDSA secondary validator. Every fleet UserOp uses this shape.

func PersonalSignUserOpHash

func PersonalSignUserOpHash(pk *ecdsa.PrivateKey, userOpHash common.Hash) ([]byte, error)

PersonalSignUserOpHash returns the 65-byte signature the weighted-ECDSA validator expects from a fleet signer when validating a UserOp.

The validator does NOT verify a raw secp256k1 signature over userOpHash. It calls signMessage({ raw: userOpHash }) on the signer in the TS SDK, which is EIP-191 personal_sign: keccak256("\x19Ethereum Signed Message:\n32" || userOpHash), then ECDSA-sign that. The on-chain validator does the equivalent ecrecover (it strips the EIP-191 prefix before recovering), so the signature must be produced over the prefixed digest.

This is the most likely place to get the signing wrong — the existing account.SmartAccountPrivateKeySigner in this module signs the userOpHash directly, which is correct for the sudo ECDSA validator but wrong for the weighted-ECDSA secondary validator we use for fleet keys. Hence a separate helper.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client sends regular-mode UserOps against a Kernel V3.1 shared account that has the weighted-ECDSA secondary validator already installed (with the caller's fleet EOA among the guardians).

func NewClient

func NewClient(cfg *ClientConfig) (*Client, error)

func (*Client) Close

func (c *Client) Close()

func (*Client) IsFleetInstalled

func (c *Client) IsFleetInstalled(ctx context.Context, kernel common.Address) (bool, error)

IsFleetInstalled wraps the package-level helper using this client's RPC.

func (*Client) SendCall

func (c *Client) SendCall(
	ctx context.Context,
	kernel common.Address,
	fleetPK *ecdsa.PrivateKey,
	msg *ethereum.CallMsg,
	customNonceKey uint16,
	waitForReceipt bool,
) (*zerodev.UserOperationResult, error)

SendCall sends a plain regular-mode UserOp through the bundler. The kernel must already have the weighted-ECDSA secondary validator installed and granted permission for executeUserOp (which is what the admin's POST /api/shared/account/email leaves behind).

type ClientConfig

type ClientConfig struct {
	RpcURL       *url.URL
	PaymasterURL *url.URL
	BundlerURL   *url.URL
	ChainID      *big.Int

	ReceiptPollingDelaySeconds int
	ReceiptPollingRetries      int
}

ClientConfig wires the RPC + chain bits the fleet client needs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL