Skip to content

Conversation

@legion2002
Copy link
Collaborator

@legion2002 legion2002 commented Jul 5, 2025

Overview

The core philosophy of the design is that the main account is the "control panel" or "admin keychain" of all subaccounts. This means that each subaccount should ideally have only 1 super admin key, which is an external key pointing to the main account.

This allows us to do key rotations and fund management easily on subaccounts, while retaining the security properties that the subaccount will not be able to use the main account's "msg.sender" to sign arbitrary data.

This is a flexible and minimal design, that allows you to do both JIT pull flows and separate balance subaccounts.

Supported SubAccount Types

Separate balance subaccounts are nicer, because they allow a lot of flexibility for the DApp, there are a lot of usecases like AI agentic execution, which might require arbitrary function selectors and calldata. It is not feasible to tightly scope the session keys for such use cases.

In general, we believe that balance aggregation and display is fundamentally an offchain UI problem. Users are already used to balance separation designs in tradFi like the separation between Current Account/Saving Account/Investment Account.

In crypto, users are already okay with depositing to hyperliquid and polymarket.
The JIT pull flow might be the wrong feature to optimize for, as the problems that we face with enforcing spending limits for all tokens, still exist in the JIT pull flow. In any case, this subaccount design is flexible enough to also allow the JIT puill flow.

Flow

image

Tests

  1. General SubAccount Flow: Test
  2. DApp Session Keys with SubAccounts: Test
  3. JIT Pull SubAccount Flow: Test

@github-actions
Copy link
Contributor

github-actions bot commented Jul 5, 2025

🤖 Bytecode changes detected! Version has been automatically bumped and EIP-712 domain versions have been updated.

@legion2002 legion2002 requested review from gakonst and jxom July 5, 2025 18:56
@legion2002 legion2002 self-assigned this Jul 5, 2025
Comment on lines +100 to +112
// This should fail because subAccount is not approved on the main account to use themainKey yet.
assertEq(
oc.execute(false, abi.encode(subAccountIntent)),
bytes4(keccak256("VerificationError()"))
);

// Verify no transfer happened
assertEq(subAccount.eoa.balance, 1 ether);
assertEq(mainAccount.eoa.balance, 9 ether);

// Now approve the subAccount to use the main account's key
vm.prank(mainAccount.eoa);
mainAccount.d.setSubAccountApproval(mainKey.keyHash, subAccount.eoa, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary for security? I understand that you have it as a protective guardrail, but if I'm signing something with my main account key, why would I also need to auth the sub-account?

Copy link
Collaborator Author

@legion2002 legion2002 Jul 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah you're right, since the main account key is already signing the digest, they don't need to also explicitly approve the subaccount to verify using their key.

One nice property of having this explicit subaccount auth though, is that you can iterate over a list of all subaccounts onchain. This might be useful to do balance aggregation in UIs.

@legion2002 legion2002 marked this pull request as draft August 11, 2025 22:44
@legion2002 legion2002 added this to the v1.0.0 milestone Sep 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants