Skip to main content

Transfer & bridge actions

Actions on POST /exchange. The request envelope, the EIP-712 signing rules, the number planes and the response shape are on that page and apply to every action here.

Send a token to another account

The plain user-to-user transfer. It moves ONE asset from the recovered signer to destination. Sender-authorized — no owner field; an agent signature therefore moves the AGENT's own balance, never the master's.

Its EIP-712 typed-data primary type is MetaFluxTransaction:SendAsset.

{
"type": "send_asset",
"params": {
"source_dex": 0,
"destination_dex": 0,
"asset": 100,
"destination": "0xabababababababababababababababababababab",
"amount": "25.5",
"to_perp": false
}
}
FieldTypeRange / valuesDescription
source_dexuint320 = spot, 1+ = a perp dexWhich ledger the amount leaves. Split standard sender, USDC: with to_perp: false the amount leaves the spot wallet (insufficient spot balance when short); with to_perp: true it leaves the perp wallet whatever source_dex says — see the standard-mode split
destination_dexuint32sameWhich ledger it arrives on
assetuint32a signing_idThe token. 100 is USDC — this is the signing_id from spot.balances[*], not the market index
destinationhex address40 hex charsRecipient
amountdecimal string> 0Amount, as a JSON string. Carried verbatim into the signed digest, then parsed
to_perpbooltrue credits the recipient's perp cross-collateral, false their spot balance
nonceuint64Optional inside params; the envelope's own nonce is the replay guard

A send that crosses the spot/perp boundary is a CONVERSION, not a move. When source_dex and destination_dex sit on opposite sides of that boundary and the asset is not USDC, the perp class has no per-asset row to receive units — it holds only a USDC-denominated collateral value. So the send is priced at the oracle mark. What is conserved is USD value, not unit count. A round trip out and back at two different marks therefore returns a different number of units, and that is profit or loss, not a defect. A same-class send, and every USDC send, is a plain move.

That path is guarded: the mark is clamped to the oracle band, a stale or unprotected mark is refused, and the perp debit is gated on free collateral.

Move your own USDC between spot and perp

Moves USDC between YOUR OWN spot balance and YOUR OWN perp cross-collateral. No recipient: both sides are the signer.

Its EIP-712 typed-data primary type is MetaFluxTransaction:UsdClassTransfer.

{
"type": "usd_class_transfer",
"params": {
"ntl": "250.5",
"to_perp": true
}
}
FieldTypeRange / valuesDescription
ntldecimal string> 0Amount in the whole-USDC plane
to_perpbooltrue = spot to perp (post collateral); refused when the spot wallet is short (insufficient spot balance; not live yet: a live node says insufficient spot USDC balance). Only USDC that no resting spot order holds can move. false = perp to spot, gated on free collateral: refused when the perp wallet cannot spare the amount (insufficient free collateral for class transfer)
info

Accepted only by a standard account that entered the mode at or after the split arm (node 0.9.7, block 5,710,001). Every other account — unified, portfolio, and a standard account that entered before the arm — holds ONE USDC balance and is refused: there is no second wallet to move to. See the standard-mode split.

warning
There is no spot_send and no usd_send

Those two names are ledger record kinds, not actions. They appear on the ledger_updates feed to say what a committed transfer DID. Sending either as an /exchange action gets unknown variant, the same error a misspelled action gets.

To send a token to someone, use send_asset. To move your own USDC between spot and perp, use usd_class_transfer.

Transfer USDC from Core to EVM

Move USDC from the Core clearing ledger to the MetaFluxEVM side: debits the sender's USDC cross-collateral on Core and mints the scale-converted 6-decimal EVM USDC to destination on the next EVM block. The MTF analogue of a Core → EVM asset transfer. Sender-authorized — no owner field; the recovered signer is the account debited. An agent signature therefore acts on the agent's own account, never the master's, so this is effectively master only (consistent with the signed-by table).

Its EIP-712 typed-data primary type is MetaFluxTransaction:CoreEvmTransfer.

{
"type": "core_evm_transfer",
"params": {
"amount": "250.5",
"to_evm": true,
"destination": "0xabababababababababababababababababababab"
}
}
FieldTypeRange / valuesDescription
amountdecimal string> 0Amount in the whole-USDC plane (the Core cross-collateral unit), as a JSON string. Carried verbatim into the signed digest, then parsed. The EVM side receives amount × 1e6 FiatToken base units (6-decimal scale)
to_evmbooltrue onlyDirection. true = Core → EVM (the only supported direction on this path). false (EVM → Core) is rejected — see below
destinationhex address40 hex chars (0x optional)EVM-side recipient (20-byte). The sender's own EVM address for a self-bridge; any EVM account otherwise (the EVM credit is a mint to this address, with no owner check)
assetuint32market asset idOptional, defaults to 0 (USDC cross-collateral). A non-zero asset moves that spot token instead, debiting the spot ledger
databyte arrayup to 4096 bytesOptional EVM calldata. When present it is run against destination after the credit lands, as a real transaction with its own receipt. See the revert rule below
destination_chain_iduint320 or the local EVM chain idOptional delivery chain. Any other value is rejected today — cross-chain delivery is not built, and the field exists so the capability has a signed slot rather than being delivered locally in silence

The payload never unwinds the credit. If data reverts, runs out of gas, or fails for any reason, the transfer still stands: the Core side was debited, the EVM side was credited, and the call is additional. Read its receipt to learn what happened — without one you could not tell a delivered-and-executed transfer from a delivered-and-reverted one.

Signing: your envelope picks the type string. An envelope carrying neither data nor destination_chain_id signs under MetaFluxTransaction:CoreEvmTransfer, byte-identically to before these fields existed — an existing client needs no change. Including either key selects MetaFluxTransaction:CoreEvmTransferV2. Presence is the selector, not emptiness: "data": [] and "destination_chain_id": 0 both count as present.

Direction (Core → EVM only). Only to_evm: true is accepted here. An EVM → Core move (to_evm: false) is rejected at commit (EVM->Core transfer must originate as an EVM burn tx, not /exchange): the EVM-side USDC debit is a FiatToken burn that only the node's EVM executor can perform, and crediting Core without a confirmed burn would mint value out of nothing. To move USDC EVM → Core, send an EVM transaction that burns the EVM USDC to the system withdraw sink; the node mirrors the burn onto the Core ledger.

Scale. Core USDC is the whole-USDC decimal cross-collateral plane; EVM USDC is a 6-decimal FiatToken integer. The conversion is evm_units = whole_usdc × 1e6. The whole-USDC amount is debited from Core the moment the action commits, so the queued EVM credit is always fully backed (zero-sum).

Funding check. The move is gated on free collateral (equity minus margin held by open positions), not raw equity — collateral backing open positions is not transferable, mirroring the bridge_withdraw / withdrawable-collateral gate. An underfunded transfer errors at commit (insufficient free collateral for core->evm transfer).

The move also charges a fee, and the fee is a quantity of MTF. It is a second debit, on top of the amount, and it is 0 today — read the fee at the end of this section before you size a transfer.

What commit does. The debit and the EVM-mint queueing are atomic at commit: amount leaves the sender's Core cross-collateral balance, and an L1 → EVM transfer entry is enqueued so the node mints the scale-converted 6-decimal EVM USDC to destination on the next EVM block. Because Core is debited at commit, the queued credit is fully backed.

Response. Non-order action → 202 Accepted admission envelope:

{ "data": { "accepted": true, "mempool_depth": 1, "nonce": 1735689600001, "action_hash": "0x..." } }

The EVM-side mint is asynchronous: the Core debit is immediate at commit, the EVM credit lands on the next EVM block.

Common errors (at commit): amount must be positive, zero destination, evm disabled (the EVM side is not enabled on this chain), EVM->Core transfer must originate as an EVM burn tx, not /exchange, insufficient free collateral for core->evm transfer, insufficient MTF or USDC for the core->evm fee, MTF price unavailable; the core->evm fee cannot be quoted in USDC, the core->evm fee does not convert to a positive USDC amount. The last three are the fee.

Gotchas.

  • destination is the EVM-side recipient and is not owner-checked — the EVM credit is a mint to that address. Double-check it; a transfer to a wrong-but-well-formed address is unrecoverable.
  • Set to_evm: true. The reverse direction is not a /exchange action — use an EVM burn transaction (see above).

The fee, in MTF

info

No fee is charged today. The parameter is 0. The fee is a network parameter, and a two-thirds-stake governance vote sets it. There is no height to wait for: charging starts the moment a vote enacts a value above 0. Watch for that enactment on validator_votes — the row carries changes[*].field: "fee.core_evm_fee_mtf". Everything below states what happens once the value is above 0. The parameter itself is documented with the fee concepts.

The fee is a quantity of MTF, charged on top of the amount you move. It is a separate debit, and it has nothing to do with the asset in the transfer: a transfer of BTC debits BTC for the amount and MTF for the fee. Both Core → EVM actions charge the same fee under the same rule, so neither core_evm_transfer nor send_to_evm_with_data is the cheaper lane.

Resolution order. The chain takes the fee from the first source that covers it:

OrderSourceRule
1your spot MTF balanceCharged as the MTF quantity the parameter names. The fee may not re-spend a balance the transfer itself needs, so a transfer of MTF needs spot MTF for the amount and the fee together
2your USDCOnly when spot MTF cannot cover the fee. The MTF quantity is quoted in USDC at the MTF reference price. The debit leaves the USDC cross-collateral balance and is gated on free collateral, so USDC held as margin by an open position cannot pay it. It must cover the fee on top of any USDC the transfer itself moves
3The transfer is refused. insufficient MTF or USDC for the core->evm fee — one string for every cause, so it does not report which balance was short

The fee is quoted before anything moves and charged after the amount leaves your balance, so a transfer refused for any reason pays no fee. The proceeds are validator revenue.

warning

A transfer can be refused for a reason that has nothing to do with the asset you are moving. MTF is priced from its own book, so step 2 needs that reference price. When the price is not usable, the chain refuses the transfer instead of charging at a guessed price:

MTF price unavailable; the core->evm fee cannot be quoted in USDC

Neither the asset in the transfer nor your balance of it is the cause. Hold enough spot MTF to cover the fee and the reference price is never read, because step 1 answers first.


Send a token to MetaFluxEVM with a payload

info

Live. Corrected 2026-08-19: this box used to say the network refused the action and told you to use core_evm_transfer instead. That stopped being true when the lane was restored and released, so the box was telling callers a live action was refused.

Writing a page ahead of the code is deliberate here. The reverse is not, and this is what it looks like. Everything below describes what runs today.

Move a token from the Core ledger to MetaFluxEVM, and optionally run an EVM payload against the recipient afterwards. Same lane and same credit as core_evm_transfer — this is that move in the Hyperliquid-compatible field shape. Sender-authorized — no owner field; the recovered signer is the account debited. An agent signature therefore acts on the agent's own account, never the master's, so this is effectively master only (consistent with the signed-by table).

Its EIP-712 typed-data primary type is MetaFluxTransaction:SendToEvmWithData.

{
"type": "send_to_evm_with_data",
"params": {
"token": 0,
"amount": "250.5",
"source_dex": 0,
"destination_recipient": "0xabababababababababababababababababababab",
"to_perp": false,
"destination_chain_id": 0,
"data": [],
"nonce": 7
}
}

All eight fields are required. No field has a default and no field may be omitted — data may be an empty array, but the key must be there.

FieldTypeRange / valuesDescription
tokenuint32a registered asset idAsset to move. For USDC send 0, not 100: both ids mean USDC, but the spot id 100 carries no EVM contract binding and is refused with asset not linked to an EVM contract — the same rule core_evm_transfer applies to its asset. The native MTF gas token always crosses. Any other token must be bound to an EVM contract or it is refused the same way — ask the chain with the markets_meta kind: "spot" read rather than guessing — see which assets can cross
amountdecimal string> 0Amount in the whole-token plane, as a JSON string. Carried verbatim into the signed digest, then parsed. An amount too small to credit is refused, not rounded down — see precision
source_dexuint320 onlyAny other value is refused. ⚠️ This is the row an existing client hits — a payload written for Hyperliquid carries source_dex: 1. This action debits exactly one ledger, the spot ledger, so no other source exists to name. The field used to be accepted and ignored; it now fails closed rather than quietly debiting a ledger you did not ask for
destination_recipienthex address40 hex chars (0x optional)EVM-side recipient (20-byte). The zero address is refused (zero destination), as on core_evm_transfer. Every other well-formed address is accepted: the credit is a mint to this address, with no owner check — read the gotchas before you send
to_perpboolfalse onlytrue is refused. The EVM side has no perp account — the credit is an EVM mint — so true selects nothing that exists. The field used to be accepted and ignored
destination_chain_iduint320 or the local EVM chain idDelivery chain. Any other value is refused. Delivery to a remote chain is not built on this lane. The field used to be signed and then ignored, so a caller who named a remote chain had the value delivered locally, in silence. It now refuses instead. To reach another chain use bridge_withdraw
databyte arrayup to 4096 bytesEVM calldata, as an array of byte integers. Send [] for none. It runs against destination_recipient after the credit lands, as a real transaction with its own receipt. Over 4096 bytes is refused — the same bound core_evm_transfer carries, because both actions stage onto the one lane
nonceuint64A transfer nonce carried with the transfer, distinct from the envelope nonce. It signs as transferNonce. The envelope nonce is still the value that orders and de-duplicates your actions

The five refusals

Each one refuses where the action once accepted and ignored. That is the whole point of the change: an ignored field is a field you signed and did not get.

What you sendAnswerWhy it refuses rather than ignoring
source_dex other than 0refusedThe action debits one ledger, the spot ledger. Ignoring the field debits a ledger the caller did not name. Historical payloads carry source_dex: 1, so this is the refusal real callers meet first.
to_perp: truerefusedThere is no perp account on the EVM side to credit. Ignoring the field delivers an EVM mint to someone who asked for a perp credit.
destination_chain_id that is neither 0 nor the local EVM chain idrefusedRemote delivery is not built. Ignoring the field delivered the value on the local chain, silently, to a caller who signed for a different one.
data over 4096 bytesrefusedThe payload bound is shared with core_evm_transfer: both actions stage onto the same lane, so a bound enforced on one door only is a bound the other door walks past.
amount that truncates to a zero EVM creditrefusedThe lane truncates twice (see below). Such an amount would debit your Core balance and credit nothing on the EVM side.

Every refusal runs before anything moves, so a refused action changes no balance. The envelope nonce is spent, as with any action that reaches commit.

Precision — a sub-quantum amount is refused, not silently rounded

Amounts are decimal strings in the whole-token plane. On the way to the EVM the lane truncates twice, both times toward zero: first to 8 decimal places, then to the token's own EVM decimals. So the smallest amount the EVM can credit is one quantum:

quantum = 10 ^ -min(8, the token's EVM decimals)
TokenEVM decimalsSmallest amount that credits
USDC60.000001
Native MTF180.00000001
Any bound ERC-20its own wei_decimals10 ^ -min(8, wei_decimals)

Two rules follow, and both exist to protect your balance:

  • Below one quantum is refused (amount truncates to a zero EVM credit). Accepting it would debit Core and credit nothing.
  • Above one quantum, you are debited the amount that is actually credited — not the amount you signed. Any sub-quantum remainder stays in your balance instead of being destroyed on the way across.

Send an amount that is already a whole number of quanta and the two values are equal. That is the shape to prefer: what you sign is then exactly what you are debited and exactly what lands.

Which Core → EVM action to use

Both actions debit the sender's exchange ledger, queue one credit, and the node mints it on the next EVM block. Neither can create value: Core is debited the moment the action commits, so the queued credit is always backed. A payload, if you send one, runs after the credit lands and never unwinds it — a revert leaves the credit standing, so read the payload's receipt to tell a delivered-and-executed transfer from a delivered-and-reverted one.

core_evm_transfersend_to_evm_with_data
Availabilitylive at every heightlive
Field shapeMTF-native (asset, destination, to_evm)Hyperliquid-compatible (token, destination_recipient, source_dex, to_perp)
Which ledger it debitsasset: 0 debits the perp collateral pool, gated on free collateral; a non-zero asset debits the spot ledgeralways the spot ledger, token: 0 included
Can move USDC held as collateralyes — this is the lane for itno
Omittable fieldsasset, data, destination_chain_idnone — all eight required
Signing type stringone of two, selected by which keys you sendone, always
A zero recipientrefused (zero destination)refused (zero destination)
The MTF feethe same fee, 0 todaythe same fee, 0 today

Use core_evm_transfer unless you are porting a client that already builds the Hyperliquid field shape. Both are live. core_evm_transfer keeps an existing signature byte-identical through its omittable fields, and it is the only one of the two that can move USDC out of the perp collateral pool.

Response. Non-order action → 202 Accepted admission envelope:

{ "data": { "accepted": true, "mempool_depth": 1, "nonce": 1735689600001, "action_hash": "0x..." } }

The EVM-side credit is asynchronous: the Core debit is immediate at commit, the EVM credit lands on the next EVM block.

Funding check — this action debits the SPOT balance, and only that. For every token, token: 0 included, the debit comes out of your spot balance of that token (insufficient spot balance).

warning

It does not reach the perp collateral pool, and core_evm_transfer does. USDC held as perp collateral is the balance account_value / withdrawable report, and this action cannot move it. Send that USDC with core_evm_transfer, which addresses the collateral pool as asset: 0 and gates the move on free collateral. Use this action for a token that sits on the spot ledger.

The MTF fee on this lane

info

No fee is charged today. The parameter is 0. A two-thirds-stake governance vote sets it, and charging starts as soon as a vote enacts a value above 0. The enactment shows on validator_votes as changes[*].field: "fee.core_evm_fee_mtf". See the fee concepts.

This lane charges the same fee core_evm_transfer charges. One rule serves both, so neither lane avoids it. The fee is a quantity of MTF, debited on top of the amount, and it has nothing to do with the token you move: a transfer of a bound ERC-20 debits that token for the amount and MTF for the fee.

Resolution order: your spot MTF balance first; then USDC at the MTF reference price, when spot MTF cannot cover the fee on top of what the transfer itself needs; otherwise the transfer is refused with insufficient MTF or USDC for the core->evm fee. The USDC step debits the USDC cross-collateral balance and is gated on free collateral, even though the amount leg debits the spot ledger.

warning

A transfer can be refused for a reason that has nothing to do with the token you are moving. MTF is priced from its own book, so the USDC step needs that reference price. When the price is not usable, the chain refuses the transfer instead of charging at a guessed price:

MTF price unavailable; the core->evm fee cannot be quoted in USDC

Neither the token nor your balance of it is the cause. Hold enough spot MTF to cover the fee and the reference price is never read.

The fee is quoted before anything moves and charged after the amount leg, so a refused transfer pays no fee. The proceeds are validator revenue. The full rule is the fee on core_evm_transfer.

Common errors (at commit, once the action is live): amount must be positive, zero destination, sendToEvmWithData debits the spot ledger only; source_dex must be 0, the EVM side has no perp account; to_perp must be false, cross-chain delivery is not built; destination_chain_id must be 0 or the local EVM chain id, sendToEvmWithData data is over the payload bound, amount truncates to a zero EVM credit, asset not linked to an EVM contract, core->evm queue is full; retry when it drains, insufficient spot balance, insufficient MTF or USDC for the core->evm fee, MTF price unavailable; the core->evm fee cannot be quoted in USDC, the core->evm fee does not convert to a positive USDC amount.

Gotchas

danger

The chain catches only the ZERO address. Validate the rest yourself. A destination_recipient of 0x0000…0000 is refused with zero destination, the same rule core_evm_transfer applies. Every other well-formed address is accepted, your balance is debited, and the credit is minted to that address with no owner check. A transfer to a wrong address is unrecoverable.

  • destination_recipient is the EVM-side recipient and is not owner-checked. Any transfer to a wrong-but-well-formed address is unrecoverable, exactly as on core_evm_transfer.
  • core->evm queue is full; retry when it drains is the one retryable error here. The rest mean the request itself is wrong; resending it unchanged fails the same way and spends another nonce.
  • The payload's success is independent of the transfer's. Do not treat a successful transfer as proof the payload ran.

Withdraw USDC to an external chain

External withdrawal over MetaBridge: debits the sender's USDC cross-collateral and queues an Outbound bridge message for validator co-signing (⅔ of active stake), after which the funds are released to dst_addr on the destination chain. Sender-authorized — no owner field; the recovered signer is the account debited. An agent signature therefore acts on the agent's own account, never the master's, so withdrawal authority is effectively master only (consistent with the signed-by table).

{
"type": "bridge_withdraw",
"params": {
"chain": "Base",
"asset": 0,
"amount": 1000000,
"dst_addr": "0xabababababababababababababababababababab"
}
}
FieldTypeRange / valuesDescription
chainenum"Base", "Arbitrum"Destination chain. Must have a registered MetaBridge contract and not be paused, or the action errors at commit
assetuint320MetaFlux asset id. Only 0 (USDC cross-collateral) is bridgeable today; any other id errors at commit (only USDC cross-collateral is bridgeable)
amountuint64> 0Amount in 6-decimal USDC base units (1000000 = 1 USDC); widened to u128 internally
dst_addrhex string40 hex chars (0x optional)Destination: a 20-byte EVM address, left-padded internally to 32 bytes. A malformed value is rejected at admission (400)

Funding check. The withdrawal is gated on free collateral (equity minus margin held by open positions), not raw equity — collateral backing open positions is not withdrawable, mirroring the pre-trade gate. An underfunded withdrawal errors at commit (insufficient free collateral for withdrawal).

What commit does. The debit and the queueing are atomic at commit: the amount leaves the cross-collateral balance, a pending-withdrawal entry is recorded (the commit outcome carries its withdrawal_id, a per-account counter), and an Outbound MetaBridge message is queued for validator co-signing. Once ⅔ of active stake has co-signed, a relayer submits the release on the destination chain — see the bridge page for the release pipeline and its dispute window.

Response. Non-order action → 202 Accepted admission envelope:

{ "data": { "accepted": true, "mempool_depth": 2, "nonce": 1735689600001, "action_hash": "0x..." } }

The HTTP response does not carry the withdrawal_id; track the commit via the returned action_hash. The destination-chain release is asynchronous (cross-chain): the L1 debit is immediate at commit, the payout follows co-signing, relay submission, and the on-chain dispute window.

Common errors (at commit): amount must be positive, chain paused (per-chain or global), chain not deployed (no registered MetaBridge contract), only USDC cross-collateral is bridgeable, insufficient free collateral for withdrawal.

Gotchas.

  • dst_addr is validated for length only — there is no checksum or ownership check. Funds released to a wrong-but-well-formed address are unrecoverable; double-check the destination.
  • A duplicate submission is a second withdrawal, not a retry — idempotency is per-nonce, and each committed bridge_withdraw debits again.

Retired: the legacy CCTP withdrawal

Retired — it has never succeeded on this chain

withdraw decodes and admits normally, so a probe reaches signature recovery and an integrator reads that as progress. It is not. Commit then refuses it:

{"error":{"code":"PRECONDITION_FAILED","message":"precondition failed: withdraw3 disabled; use bridge_withdraw"}}

The disable height is 0 on both testnet and mainnet. This action has been refused at every commit since genesis. No height changes this, and no release turns it on.

Use bridge_withdraw. It is the only live path out of the chain, it carries a real destination address, and it is gated on free collateral.

The tag stays on the wire so that old fixtures still decode. Its four fields — asset, amount, destination_chain_id and use_cctp — are all required at decode, and they are listed here only so a reader can identify the action. They are not a shape to build against, and the signed digest, MetaFluxTransaction:Withdraw, is not one to implement.

There is no CCTP code path on this chain. use_cctp selects nothing.


Non-bridged actions

The following draft action names are not wired on the MTF-native /exchange handler. Posting them returns 400 with ACTION_UNSUPPORTED (recognized-but-unmapped stubs) or INVALID_REQUEST (no native tag at all). They are documented here only to redirect integrators to the supported path.

Draft nameNative tagDispositionUse instead
Order (multi) / Cancel (multi)Single vs. batch are distinct tagssubmit_order + batch_order; cancel_order + batch_cancel
UpdateMarginModeNo native actionis_isolated flag on update_leverage
MultiSigmulti_sigBridged and executing. Post it as a normal multi_sig envelopemulti_sig acts; convert_to_multi_sig_user registers the roster
RegisterReferrerNot bridgedset_referrer binds by address
UsdcTransfer / SpotTransferUser-to-user transfer flows not bridged
WithdrawUsdcwithdrawRetired. Recognized and admitted, then rejected at commit — "withdraw3 disabled; use bridge_withdraw". The disable height is 0, so it has never succeeded herebridge_withdraw withdraws USDC cross-collateral externally
(BOLE pool)borrow_lendBridged and live. params.kind "Lend" / "UnLend" / "Repay" open to any account; "Borrow" refused unless the sender is an approved liquidator
(vault distribute)vault_distributeBridged and live — a follower's own self-service depositvaults
(Earn pool config)create_earn_poolValidator governance, never a user action. createEarnPool (201) is a ⅔-stake vote submitted through node governance. It is the only way an Earn pool gets a non-zero borrow rate — see why that mattersearn_deposit auto-creates a pool at rate 0
(PM lifecycle)pm_enroll / pm_unenrollpm_enroll has no native tag. pm_unenroll is a bridged alias (no params) for the canonical action's enroll:false form; pm_rebalance retired → rejected as an unknown actionuser_portfolio_margin
(cross-chain)Not an /exchange action at all. Not in the action enum: it fails decode and returns 400 INVALID_REQUEST (unknown variant), not ACTION_UNSUPPORTEDCrossChainSend, CoreWriter action 19 — a MetaFluxEVM call, not an /exchange post
(Metaliquidity set)set_metaliquidity_setValidator governance, never a user action. Decodes, then refused ACTION_UNSUPPORTED (read the code, not the message). A ⅔-stake vote; a valid validator signature is refused here toogovernance and validator actions
(spot value adjust)gov_adjust_spot_valueValidator governance, never a user action. Same decode-then-refuse answer. params.value is hashed verbatim, so quorum needs one byte-identical spellinggovernance and validator actions
(validator lane)gov_vote vote_global set_mark_mode set_pm_shock_grid arm_features approve_upgrade c_validator vote_app_hashValidator governance or self-service, never a user action. Decode, then refused ACTION_UNSUPPORTED; a valid validator signature is refused here toogovernance and validator actions
(retired alias)encrypted_order_submitRetired from the public surface — rejected 400, error points at the canonical spellingsubmit_encrypted_order
UserDexAbstractionuser_dex_abstractionRetired at the 0.7.0 re-genesis → ACTION_UNSUPPORTED. One unified account, so nothing to abstract— (no replacement)