DocsReference

Vaults & security

Two small contracts hold the whole system together. This page describes what they do, what the attestation is, and, most importantly, what nobody, including Dibs, can do.

The contracts#

HandleVaultFactory#

One per deployment. It maps handle keys to vaults and is the only thing that can bind a wallet to a handle.

FunctionWhoWhat
predict(handleKey)AnyoneThe vault address for a key, whether or not it's deployed yet (CREATE2, salt = handle key).
deploy(handleKey)AnyoneDeploys the vault at that address. Idempotent; usually done as part of the first claim.
bind(handleKey, wallet, deadline, sig)Anyone with a valid attestationBinds the wallet after verifying the attestor's EIP-712 signature, the per-key nonce and the deadline.
bindAndClaim(…, sponsorFee, sig)Anyone with a valid attestationDeploy if needed, bind, then pay the vault's ETH: the attested fee to the submitter, the rest to the wallet. One transaction.
claimSponsored(handleKey, asset, fee, …)Anyone with a valid attestationPay ETH or an ERC-20 asset to the bound wallet minus the attested fee for the submitter. Never paused.
proposeAttestor / acceptAttestorOwner, then the new attestorTwo-step rotation of the attestation key.
pause / unpauseOwnerStops new bindings. Never stops claims to already-bound wallets.

HandleVault#

One per handle, deployed as an EIP-1167 minimal proxy of a single implementation whose address is fixed in the factory. It owns nothing but the fees that Pons pays it, and it can only pay them to the bound wallet.

FunctionWhoWhat
claim()AnyonePull ETH from the Pons escrow and send the vault's whole ETH balance to the bound wallet.
claimToken(asset)AnyoneSame for an ERC-20 fee asset (a stock-paired coin's quote token).
claimSponsored / claimTokenSponsoredFactory onlyThe same payouts with a fee for the submitter, capped at 20% of the payout and 0.002 ETH for ETH.
sweep(token)AnyoneAsk the coin's curve to sweep accrued fees into the escrow (Pons automation also does this).
withdraw / withdrawTokenBound wallet onlySend an amount to an arbitrary address.
redirect(token, newRecipient)Bound wallet onlyAsk Pons to move a coin's future fees elsewhere. Subject to Pons's 3-day timelock.
setBuybackEnabled(token, on)Bound wallet onlyToggle the coin's buyback flag on Pons.

The attestation#

The one off-chain input to the system is the statement “this handle key may be bound to this wallet”. Dibs signs it only after:

  • the user signed in with the X or GitHub account whose permanent id hashes to that handle key, and
  • the user signed a fresh message from the wallet, proving they control it.
EIP-712 typed data checked by the factorysolidity
Bind(bytes32 handleKey, address wallet, uint256 nonce, uint256 deadline, uint256 sponsorFee)
Claim(bytes32 handleKey, address asset, uint256 fee, uint256 nonce, uint256 deadline)

domain:   name "Dibs HandleVaultFactory", version "2", chainId 4663, verifyingContract = factory
nonce:    factory.nonces(handleKey), increments on every bind or sponsored claim
deadline: now + 10 minutes
fee:      what the relayer is repaid from the payout; the vault rejects > 20% or > 0.002 ETH

Both signatures are single-use (the nonce) and short-lived (the deadline). Neither can move funds anywhere but the bound wallet and the attested fee to whoever submitted the transaction; the wallet had to prove itself, and the fee is capped in code.

What nobody can do#

ActorCannot
DibsMove, redirect or pause payouts for a bound wallet. Change a vault's code. Take a fee. Unbind a wallet.
The attestorPay anyone but a wallet that proved itself, or touch an already-bound handle without a fresh sign-in.
The relayerAnything beyond submitting attested calls: it is repaid the attested fee and nothing more, and every payout goes to the bound wallet.
A launcherChange the fee recipient after launch, or claim the tagged account's fees.
AnyoneDeploy a different contract at a handle's vault address.

Addresses and verification links are on the developers page.