Hi MetaMask team,
We are building a game on Polygon (POL as the native asset) where users execute in-game actions by calling `Game.join(uint8)`. To remove the per-transaction popup friction, we want to grant a session account scoped execution authority. The minimum scope we need is:
- target restricted to a single contract (`Game`)
- method restricted to a single selector (`join(uint8)`)
- native POL value capped per stream or per period
- timestamp expiry
Description:
Add a new family of Advanced Permission types that combine a target/selector restriction with a native-token (or ERC-20) value cap. The currently supported permission types — native-token-stream, native-token-periodic, erc20-token-stream, erc20-token-periodic, erc20-token-revocation — only express value caps and timing. None of them restricts the call target or the function selector.
Proposed new permission types:
ts
// Native token, streaming
{
type: “native-token-function-call-stream”,
data: {
target: Address,
selectors: Hex[], // 4-byte function selectors
amountPerSecond: bigint,
initialAmount?: bigint,
maxAmount?: bigint,
startTime?: number,
justification?: string
}
}
// Native token, periodic
{
type: “native-token-function-call-periodic”,
data: {
target: Address,
selectors: Hex[],
periodAmount: bigint,
periodDuration: number,
startTime?: number,
justification?: string
}
}
ERC-20 equivalents (erc20-token-function-call-stream, erc20-token-function-call-periodic) would cover token-paid contract calls in the same shape.
Suggested confirmation UI copy:
“This dapp can call join(uint8) on 0x1234…ABCD and spend up to 100 POL over 12 hours.”
The required onchain primitives are already shipped and audited in the Delegation Framework: AllowedTargetsEnforcer, AllowedMethodsEnforcer, NativeTokenStreamingEnforcer, NativeTokenTransferAmountEnforcer. The remaining work sits at the ERC-7715 schema level — permission type definition, handler in the Gator Permissions Snap, and the permission picker UI — not at the smart contract level.
Purpose:
Concrete use case: game on Polygon. Users place bets by calling Game.join(uint8) with a native POL value. To remove per-transaction popup friction, we need to grant a session account scoped execution authority with:
-
target restricted to the Game contract only
-
method restricted to the join(uint8) selector only
-
native POL capped per stream or per period
-
timestamp expiry
Both supported paths fail today:
-
ERC-7715 native-token-stream — no target / selector field. If the session key is compromised, an attacker can drain POL within the stream limit to any address. Unsafe for a betting product where the session key lives in the browser. We also confirmed that reusing a native-token-stream permission context to call join(uint8) reverts onchain with ExactCalldataEnforcer:invalid-calldata, because the streaming context is shaped for plain native transfers, not contract calls.
-
Custom ERC-7710 delegation with caveats (AllowedTargets + AllowedMethods + NativeTokenStreaming) — blocked at the MetaMask Extension signing layer:
InternalRpcError: An internal error was received.
Details: External signature requests cannot sign delegations for internal accounts.
The rejection happens in MetaMask/core → packages/signature-controller/src/utils/validation.ts → validateDelegation().
We understand the security reasoning behind blocking Path B — an unconstrained delegation typed-data is not human-readable and could expose the entire wallet — and we agree it should remain closed for general dapps. Hence this request for a new Advanced Permission type that fills the schema gap safely, with a human-readable confirmation UI.
Beyond our use case, this gap blocks essentially every non-trivial agent or session-execution pattern that needs to call a specific contract method instead of transferring raw value: gaming, DeFi strategy bots, perp / auto-rebalance agents, scheduled liquidations, vesting claims, on-chain voting agents. Today the only escape routes are (a) move the signer outside MetaMask using an embedded wallet, or (b) redesign the protocol around deposit/escrow. Both undermine the value proposition of Advanced Permissions for these workflows.
Extension/Mobile/Both:
Both. The schema itself is platform-agnostic. The immediate, observable blocker is on the Extension (signature-controller validateDelegation), but a new permission type with this shape would benefit Mobile equally as Advanced Permissions roll out there.
Images/Attachments:
No screenshots — the failure occurs at the signing layer before any UI is rendered, so there is nothing visible to capture. Reference material:
- Source of the rejection: MetaMask/core, packages/signature-controller/src/utils/validation.ts, function validateDelegation()
Happy to share a minimal PoC repo, full error logs and the exact typed-data payload, or to open a draft schema PR against MetaMask/snap-7715-permissions on request.
t handle: @me2jay