marmot

Marmot docs

20 pages, from the idea to the error codes

Concepts

What can be announced

Five kinds of announcement, and how they are read.

The kinds

KindFunctionWhat runs
CallqueueCall(to, value, data)The vault calls to with value and data. Reverts if the call fails.
Call (send)queueTransfer(token, to, amount)ETH: a call with value and empty data. Token: transfer(to, amount) on the token.
SetDelayqueueSetDelay(delay)The wait changes (5 minutes to 30 days).
SetGuardianqueueSetGuardian(g)The guardian is replaced. Same validity rules as at creation.
SetOwnerqueueSetOwner(o)The owner is replaced and the epoch moves.

Reading an announcement

Every announcement is public in the Queued event and in getOp(id). The engine turns it into a sentence:

Send 1.5 ETH to 0xA7E1...A6C1
Send 100 USDC to 0x21f3...a831
Let 0x91aa...30c2 spend UNLIMITED USDC
Change the waiting time to 3 d
Replace the guardian with 0x7e3d...145d
Hand the vault to a new owner 0x4faE...432E
Call 0x1234...abcd (0x38ed1739) with 0.2 ETH

Anything the engine does not recognise is shown as a generic call with its 4-byte selector. Treat an unreadable call as suspicious, and check the target and selector before letting it ripen.

Approvals deserve extra care

An approve is the sharpest tool: once it runs, the spender can take the tokens at any time, and the vault has no say. That is why the lookout flags unlimited approvals. The waiting room protects you only before the approval runs.

NFTs and other assets

The vault receives NFTs sent with a plain transfer. To move them, announce a queueCall on the NFT contract (for example transferFrom). The helper queueTransfer only covers ETH and fungible tokens.

Order does not matter

Announcements are independent. They can ripen and run in any order, and one failing does not block the others. A failing call simply reverts and stays pending until it expires or is cancelled.