client.autoWithdraw manages the scheduled auto-withdraw rule of the root account or a subaccount.
On each UTC slot of its schedule, a rule pays each listed asset's balance, in kind, to a destination
on the account's external withdraw whitelist. Every method is authenticated and account-scoped, so
each input accepts an optional account field ("main", "active", or { subaccountId }). See Account scoping for how the default resolves.
API keys can read rules and runs when their policy grants read-auto-withdraw (or manage-auto-withdraw), and only for their own account; otherwise they throw PermissionError.
Changing a rule needs a session login with withdraw rights and a fresh single-use step-up proof
passed as options.stepUpToken. Without one, setRule and disableRule throw StepUpRequiredError or SessionElevationRequiredError; check isFreshStepUpRequiredError before retrying with a new token. See MFA.
Methods
| Method | Summary |
|---|---|
getRule | Read the account's latest rule version, or null. |
setRule | Create the rule, or replace its latest version. |
disableRule | Stop the rule by writing a disabled version. |
listRuns | Page through the account's runs and their payouts, newest first. |
getRule(input?, options?)
Returns the account's latest AutoWithdrawRule, or null when the account never had a rule.
const rule = await client.autoWithdraw.getRule();
console.log(rule?.version, rule?.enabled, rule?.schedule.cadence);setRule(input, options?)
Creates the account's rule, or replaces its latest version, and returns the new version. Pass the
version you are replacing as expectedVersion: 0 when the account has no rule yet, otherwise its
latest version.
const current = await client.autoWithdraw.getRule();
const rule = await client.autoWithdraw.setRule(
{
expectedVersion: current?.version ?? 0,
schedule: { cadence: "weekly", weekday: "friday", minuteOfDay: 17 * 60 },
destinations: [
{
assetId: 2,
destinationChainId: 1,
destinationAddress: "0xabc...",
minAmount: "100",
maxAmount: "5000",
},
],
minUsdValue: "50",
},
{ stepUpToken }
);setRule and disableRule throw RevisionConflictError. Refetch the rule and ask the user to review the change; do not
retry the same write automatically.SetAutoWithdrawRuleInput
| Field | Type | Required | Notes |
|---|---|---|---|
expectedVersion | number | yes | The version this change replaces; 0 when there is no rule yet. |
schedule | AutoWithdrawScheduleInput | yes | The UTC run slot. See below. |
destinations | AutoWithdrawDestinationInput[] | yes | 1 to 32, at most one per asset. |
minUsdValue | decimal string | null | no | Least USD value one payout pays. Omit or null for no minimum. |
account | AccountScope | no | Scope override. |
schedule is tagged by cadence, and each cadence takes only its own fields. Any other field
throws ValidationError. All times are UTC.
cadence | Fields |
|---|---|
"hourly" | minuteOfHour (0 to 59) |
"daily" | minuteOfDay (0 to 1439) |
"weekly" | weekday, minuteOfDay |
"biweekly" | weekday, minuteOfDay, anchorDate |
"monthly" | dayOfMonth (1 to 31), minuteOfDay |
minuteOfDay counts minutes after 00:00 UTC. weekday is "monday" through "sunday". A dayOfMonth past the end of a shorter month runs on its last day. anchorDate is a YYYY-MM-DD UTC date in a week the biweekly rule runs; weeks start on Monday, and the returned rule carries
that week's Monday.
Each destination pays one asset to one external-chain address:
| Field | Type | Notes |
|---|---|---|
assetId | number | Ledger asset paid. |
destinationChainId | number | External destination chain ID. |
destinationAddress | string | Must be on the account's external withdraw whitelist. |
minAmount | decimal string | A run pays the asset only once the payable amount reaches this. |
maxAmount | decimal string | The most one run pays. Greater than 0 and at least minAmount. |
Amounts take up to 18 decimal places. minAmount must be at least the route's withdrawal minimum.
A balance below the minimums stays on the account for a later run, and a balance above maxAmount pays maxAmount and keeps the rest. With minUsdValue set, each run values each asset at the
current index price; when no current price is available, that asset is skipped with reason price_unavailable.
A schedule the backend refuses fails with detail.service === "withdraw" and detail.code === "INVALID_AUTO_WITHDRAW_SCHEDULE".
disableRule(input, options?)
Disables the rule and returns the disabled version, which has enabled: false and no
destinations. Pass the latest version as expectedVersion. Needs a fresh stepUpToken.
await client.autoWithdraw.disableRule({ expectedVersion: rule.version }, { stepUpToken });listRuns(input?, options?)
Returns { runs, nextPageToken }, newest first. limit is 0 through 100; 0 or omitted uses the
server default of 20. Pass the previous nextPageToken as pageToken to continue; an empty nextPageToken means there are no more runs.
let pageToken = "";
do {
const page = await client.autoWithdraw.listRuns({ pageToken, limit: 50 });
for (const run of page.runs) console.log(run.runSeq, run.state, run.steps.length);
pageToken = page.nextPageToken;
} while (pageToken !== "");Shapes
Amounts are decimal strings and times are epoch milliseconds.
import type { AutoWithdrawRule, AutoWithdrawRun, AutoWithdrawStep } from "@polyester/sdk";
interface AutoWithdrawRule {
subaccountId: string; // public subaccount ID, "" for the root account
version: number; // starts at 1; each change or disable creates the next version
enabled: boolean;
schedule: AutoWithdrawSchedule; // { cadence: "unspecified" } for a cadence this build does not know
destinations: AutoWithdrawDestination[]; // ordered by assetId
createdAt: number;
pause: AutoWithdrawPause | null; // set when the rule paused itself
minUsdValue: string | null; // null when the rule has no USD minimum
}
interface AutoWithdrawRun {
runSeq: string; // the account's run number, one higher per run
ruleVersion: number; // the rule version the run executes
scheduledFor: number;
state:
| "planned"
| "paying"
| "completed"
| "partially_failed"
| "failed"
| "skipped"
| "unspecified";
reason: AutoWithdrawRunReason | null; // why the run was skipped
steps: AutoWithdrawStep[]; // one per destination, empty while planned
createdAt: number;
finishedAt: number | null; // null while in progress
}
interface AutoWithdrawStep {
assetId: number;
destinationChainId: number;
destinationAddress: string;
available: string; // available balance when the run started
amount: string; // what the step pays; "0" when skipped
valueUsd: string | null; // null without a USD minimum or a price
state:
"pending" | "submitting" | "submitted" | "completed" | "failed" | "skipped" | "unspecified";
reason: AutoWithdrawStepReason | null; // why the step was skipped or failed
intentId: string | null; // set once the withdrawal is accepted
txHash: string | null; // set once the withdrawal completed
}Only the latest rule version runs. A run in progress keeps the version it started with but pays
nothing further once that version is no longer the latest. A step's intentId follows the same lifecycle as a user withdrawal.
pause is { assetId, reason, pausedAt }. Writing a new version resumes the rule. Reasons are
strings, and reasons newer than this SDK build pass through unchanged:
| Field | Known reasons |
|---|---|
| Pause | destination_not_whitelisted, destination_invalid, authority_revoked (the person who set the rule may no longer change it or withdraw from the account) |
| Run | nothing_to_pay, price_unavailable, rule_superseded |
| Step | below_minimum, price_unavailable, rule_superseded, destination_not_whitelisted, authority_revoked, gateway_capacity_insufficient, withdrawal_released, withdrawal_failed |
For price_unavailable and gateway_capacity_insufficient, the funds stay on the account for a
later run.
Related
- Withdrawals for one-off signed withdrawals.
- Address book for the external withdraw whitelist.
- MFA for obtaining a
stepUpToken. - Lifecycle to follow each payout's withdrawal.