Security
Keys never leave Inodra
Each tank has its own Ed25519 key. Inodra generates it, encrypts it, and stores it. The key is decrypted only to sign. It is never returned by any API, never shown in the dashboard, and never exported.
Inodra never holds user keys. Users sign with their own wallets.
The sponsor signature only pays gas
A Sui transaction names a sender and a gas owner. The tank is the gas owner. The sponsor signature says "the gas owner agrees to pay gas for these bytes". It cannot:
- Move objects owned by the tank. Objects are owned by the sender or by shared state.
- Withdraw from the tank's address balance beyond gas. Withdrawals come from the sender.
- Change the transaction. The user signature covers the same bytes.
The user signature is verified before Inodra signs. A transaction the user did not sign is never sponsored.
Structural checks
Inodra decodes every transaction and rejects it when:
- The sender is a tank address. A tank can never send a transaction. Code
SENDER_IS_SPONSOR_ADDRESS. - Gas payment is not empty. The tank pays from its address balance only. Code
GAS_PAYMENT_MUST_BE_EMPTY. - The gas coin is used as an argument.
tx.gaswould let the sender spend the tank's SUI. CodeGAS_COIN_ARGUMENT. - A funds withdrawal names the gas owner. Withdrawals must come from the sender. Code
WITHDRAW_FROM_NOT_SENDER. - The transaction calls
0x2::address_aliasor reads the alias state object. Aliases could redirect signing authority. CodesADDRESS_ALIAS_CALLandADDRESS_ALIAS_STATE_INPUT. - The gas budget or price is outside the tank's bounds. Codes
BUDGET_EXCEEDS_TANK_MAXandGAS_PRICE_TOO_HIGH.
These checks run on the bytes, before any node call, and cannot be turned off.
Inodra verifies the user signature but does not require the signer to equal the sender, because an alias signer is allowed to differ. The node is the authority on that. A caller with a valid Sponsor key can therefore submit transactions the node rejects. Each one costs an admission slot that is given back on rejection, and nothing is charged.
No withdrawals through the sponsor
There is no API that moves SUI out of a tank on request. The only ways SUI leaves a tank are:
- Gas for sponsored transactions, within the rules.
- A refund signed by an organization owner or admin with the destination wallet.
- Inodra's fee sweep, which moves only the owed fees.
Tank addresses use no aliases. Users cannot change who signs for a tank.
API key scopes
All /v1/gas/* routes need the Sponsor scope. A key with only Data or Manage gets 403 INSUFFICIENT_SCOPE.
- Give Sponsor to as few keys as possible.
- A leaked Sponsor key can spend tank funds within the tank's rules until you revoke it. Revoke keys from the dashboard.
- Manage does not include Sponsor. Sponsor does not include Manage.
Origin allowlist
If a Sponsor key runs in a browser, set an allowed origins list on the key. Requests from other origins are rejected. Pair this with tight allowedTargets and allowedSenders rules.
Rate limits
- Your plan's request rate limit applies to
/v1/gas/*like any other route. dailyCapMistbounds total spend per day.maxSponsorshipsPerSenderPerDaybounds what one wallet can extract.- The free plan has a hard cap of 10 sponsorships per month per network.
Kill switch
Inodra can pause sponsorship for all tanks. When it does:
POST /v1/gas/submitreturns503 SPONSORSHIP_DISABLED.GET /v1/gas/configreturns"sponsorshipAvailable": false.- Refunds pause. Deposits, balances, and tank settings keep working.
- The dashboard shows a banner.
Clients should read sponsorshipAvailable before they build and show a retry message when it is false.
Reconciliation
Inodra compares each tank's ledger with its on-chain balance every hour. If the chain holds less than the ledger says, the ledger is corrected at once so the tank never sponsors more than it holds. Large drifts freeze the tank and alert Inodra.
While a tank is frozen nothing signs with its key: sponsorship, customer refunds and Inodra's own sweeps all stop until Inodra has reviewed the tank and unfrozen it.