Skip to main content
Your frontend’s BuilderCodes earnings go to a payout wallet. That wallet can be a Safe multisig on Sei, so moving the money on-chain out of the Safe needs your owners’ approval. This guide shows how the Safe logs in to Monaco, checks what it has earned, sets your builder fees, and withdraws the earnings to itself. Everything runs from one script. Each run logs the Safe in, which needs your Safe’s usual number of owner approvals.

Before you start

  1. Send Monaco your Safe address on Sei mainnet, with the name of your frontend. Monaco sets it as your payout wallet and lets it log in. Wait for Monaco to confirm before you run the script.
  2. Have your owners ready. Each login asks the owners to confirm one message in the Safe app. Enough of them to meet your Safe’s threshold must confirm within 30 minutes.
  3. Pick one owner to run the script. The script needs that owner’s private key. It uses it to propose each login message and to send the final withdrawal transaction, so the owner’s address needs a little SEI for gas. Owners must be ordinary wallets, not other Safes.
  4. Install the tools: Node.js 22 or later, then:

How the login works

A Safe has no private key, so it cannot sign Monaco’s login message the way a normal wallet does. Instead:
  1. The script asks Monaco for a login message.
  2. The owner running the script signs it and posts it to the Safe app, where it appears under Messages.
  3. The other owners open the Safe in the Safe app, go to Messages, and confirm it.
  4. Once enough owners have confirmed, the script sends the combined signatures to Monaco. Monaco asks your Safe contract whether they are valid (EIP-1271) and logs the Safe in.
Approving a login gives that session full control of the Safe’s Monaco balance until the session ends, including withdrawing it to any address. Owners confirm only the login, not each action after it. Confirm a login message only when you know who started it and expect it. This script withdraws only to the Safe and logs out when it finishes, which ends the session.
The session belongs to your Safe and your frontend. The config, fee and payout-history calls cover only that frontend. The withdrawable balance belongs to the Safe itself: if the Safe is the payout wallet for more than one frontend, it holds their earnings together, and WITHDRAW=1 withdraws all of it. Use a separate Safe for each frontend to keep them apart.

The script

Save this as safe-payout.ts:
MONACO_CLIENT_ID is your frontend’s client ID, the same one your app passes to sdk.login. The SDK needs seiRpcUrl whenever you pass your own wallet client, as this script does.

Check what you have earned

Run the script with no options:
Confirm the message in the Safe app when asked. The script then prints:
  • your current taker and maker builder fees;
  • Earned: your frontend’s lifetime totals per payout kind — REVENUE_SHARE, BUILDER_FEE (paid by your takers) and BUILDER_MAKER_FEE (paid by your makers). These count every payout wallet your frontend has used;
  • Available to withdraw: what this Safe can withdraw right now.
Amounts are raw token units. USDC has 6 decimals, so 1500000 is 1.5 USDC. See BuilderCodes for more. Run this first, before you withdraw, to check the Safe logs in and the numbers look right.

Set your builder fees

Add TAKER_BPS, and MAKER_BPS if you want to change the maker fee too (leaving it out keeps the current maker fee):
Both are basis points (1 bps = 0.01%) charged on top of Monaco’s fees: the taker fee on your users’ taker fills, and the maker fee on fills of their resting orders. Each must be between 0 and the cap the script’s config reports (builderFeeCapBps, never above 100). You get two changes in any rolling 24 hours; setting the fees you already have does not use one. New fees reach orders within a few seconds. The full rules are in BuilderCodes.

Withdraw to the Safe

Add WITHDRAW=1:
The script:
  1. moves any earnings waiting in the Safe into its Monaco balance (no gas);
  2. starts a withdrawal of the Safe’s whole USDC balance on Monaco to the Safe’s own address;
  3. waits until the withdrawal is ready on-chain, usually a few minutes (it gives up after an hour and tells you how to finish later);
  4. sends the withdrawal transaction from the owner’s address, which pays the gas. The funds always go to the Safe, whoever sends it.
Keep the withdrawal number the script prints. If the script stops after starting the withdrawal, the money has already left your Monaco balance and is waiting for step 4. Do not run WITHDRAW=1 again; finish that withdrawal instead. This does not log in, so the owners do not need to confirm anything:
If moving the earnings into the Safe’s balance fails with a 503, do not retry straight away: see unknown outcomes.

Troubleshooting