Skip to main content

Endpoints

The contract exposes 55 state-changing endpoints — 30 restricted to the owner, 25 callable by anyone with the right to do so. Read-only calls are on Views.

Generated from the build output

Contract crate corelayer 1.0.0, built with multiversx-sc 0.66.2 on rustc 1.94.1 (e408947bf 2026-03-25). The ABI itself is served at /abi/corelayer.abi.json.

Deploy​

Deployed PAUSED. No sync call happens here: the deep venue validation is setSwapVenue, which the launch script must run before the first deposit (venue_validated gates deposits). Arguments come from deploy/networks.json and from nowhere else (D-018).

ArgumentType
chain_idbytes
usdc_token_idTokenIdentifier
wegld_token_idTokenIdentifier
pair_addressAddress
wrapper_addressAddress
initial_tariffu64
ru_schedule_hasharray32<u8>

Upgrade​

No arguments, ever. Requires ALL FOUR money scopes paused (K-19): paused alone does not stop renew*, settleUsage or try_distribute, which would otherwise run on unverified code from the first block after the upgrade. The contract STAYS paused in all four scopes; the owner unpauses scope by scope after the post-upgrade verification. The owner check is written out rather than declared with #[only_owner]: the derive macro applies that attribute to #[endpoint] methods only and drops it silently on #[upgrade]. It is defence in depth (SPEC-DEVIATIONS DEV-03) — the protocol already refuses an upgradeContract transaction from anyone but the contract owner — but INV-K7 names upgrade as owner-only, and a guard that lives outside the code cannot be asserted by a test.

No arguments.

Open endpoints​

Anyone may call these; the contract checks the caller’s right inside. payable endpoints take the payment token in the call itself.

setReporter​

Owner: immediate. Operator: effective after REPORTER_CHANGE_DELAY_MS (K-20); the operator's instant incident tool is pauseSettlement().

ArgumentType
reporterAddress

pause​

No arguments.

pauseDeposits​

No arguments.

pauseSettlement​

No arguments.

pauseDistribution​

No arguments.

pauseRenewals​

No arguments.

subscribe​

ArgumentType
tier_idu32
monthsu8
max_priceu64
referenceoptional<bytes>variadic

renew​

Permissionless, idempotent, never paused, never reverts for a business reason. An unknown account answers NoAccount instead of reverting.

ArgumentType
accountAddress
ReturnsType
—RenewOutcome

renewMany​

The same, per address, independently. An EMPTY batch is a no-op rather than a revert: this endpoint is relayed at our own cost. Totals is read ONCE before the loop and written at most ONCE after it, the §4.1 cache pattern settleUsage already follows. Reading and writing the one global key per account cost a 50-account batch up to 50 loads and 50 stores (~6.6 M gas at the 02 §6 schedule) that the §13.2 budget does not carry, and renewMany is an INTERNAL free-relay call whose declared gasLimit C-13 caps at 1.5 × the measured figure.

ArgumentType
accountsvariadic<Address>variadic
ReturnsType
—variadic<RenewOutcome>variadic

setAutoRenew​

Sets the flag and the two guards; it does NOT renew (S §4). Zero never means "unlimited": an autonomous buyer must state its ceiling.

ArgumentType
enabledbool
renew_tier_idu32
max_renew_priceu64

setPayg​

Four arguments, exactly (K-04): a client that encodes three gets an argument-decode revert that OUR relayer pays for on the free flow. enabled = false never releases escrow — it only starts the close. Disabling twice keeps the FIRST payg_disabled_at_ms, so the 1 h and 7 d clocks cannot be restarted by spamming the free call. Split gate (SPEC-DEVIATIONS DEV-17): turning PAYG ON is subject to paused (Gate::All), turning it OFF is not (Gate::Open). setPayg is the ONLY way to raise ACC_FLAG_PAYG_CLOSING and start the 1 h / 7 d clocks, and releaseEscrow is deliberately never paused so that "a dead or hostile reporter can never lock user funds". With one Gate::All for both directions the operator's warm pause() key froze every payg_escrow in the system indefinitely while settleUsage (Gate::Settlement) kept debiting it. Closing takes no fee, needs no venue and only ever moves the account towards release, so it cannot be used to bypass a pause.

ArgumentType
enabledbool
budgetu64
auto_topupbool
max_payg_priceu64

releaseEscrow​

The fallback release (S §5.3 case 2): permissionless, never paused, and it can only move the account's OWN escrow into its OWN credits, once per PAYG close. The normal path is the reporter's closing line. An address with no record answers ERR_RELEASE_NOT_DUE, not ERR_NO_ACCOUNT: §12.3 gives this endpoint exactly two preconditions and §12.1's "the record must exist" rule is for endpoints whose CALLER is the account. A permissionless sweeper walking a list of addresses must read "nothing to release" for an unknown one, not a billing failure. The lazy block roll runs first, exactly as setPayg does, so the period_id of the emitted escrowMoved is the period now really falls in and not the last id of a block that already ended.

ArgumentType
accountAddress

settleUsage​

ArgumentType
batch_idu64
window_end_msu64
usage_rootarray32<u8>
totalsBatchTotals
linesbytes

setSettleCaps​

Operator or owner. K-20: the operator may only LOWER the window cap — a stolen warm key cannot turn the 50 USDC/h reporter bound into 1,000.

ArgumentType
max_settle_per_windowu64
sender_fee_ruu32

addSenders​

ArgumentType
max_feeu64
sendersvariadic<Address>variadic

removeSenders​

Fee-less, and it never refunds: the slot was paid for when it was taken. Never blocked by paused (Gate::Open, SPEC-DEVIATIONS DEV-17). This is "the payer's only defence against a compromised sender key", and isAuthorizedSender — which the relay backend reads to decide whether to keep serving that key — is a view and is never paused either. Leaving it under Gate::All meant the operator's warm pause() key kept a stolen sender key authorised and burning the customer's quota until the cold owner key could unpause. It takes no fee and only ever REMOVES state, so it cannot be used to bypass a pause.

ArgumentType
sendersvariadic<Address>variadic

activateRelayers​

Registered -> Active and Draining -> Active (false alarm or planned maintenance). Pushes start with the very next distribution.

ArgumentType
entriesvariadic<multi<Address,u32>>variadic

drainRelayers​

Active -> Draining: weight 0 and out of activeSet in the SAME transaction, so the very next payment no longer pays it. Deliberately unguarded — no share bound, no last-in-shard check — because an incident must never be blocked by a bound.

ArgumentType
addressesvariadic<Address>variadic

retireRelayers​

Draining -> Retired after MIN_DRAIN_MS, or Registered -> Retired immediately (a spare whose cold key is lost or suspect). Terminal, and the tombstone is permanent.

ArgumentType
addressesvariadic<Address>variadic

setRelayerWeights​

Active rows only. One relayerWeightsChanged event per CALL, never one per relayer, and one activeSet store per call.

ArgumentType
entriesvariadic<multi<Address,u32>>variadic

distributeRelayerPool​

Permissionless ("no keeper" purity): anyone may flush once the gates pass. A call by the owner or the operator is FORCED and bypasses the gates — used after a weight change, after draining a compromised relayer, or to empty the pool before an upgrade. Never reverts when the gates are closed; it returns false.

No arguments.

ReturnsType
—bool

setDistributionParams​

Operator or owner. The bounds exist so that a stolen operator key can delay pushes by at most 7 days / 100 EGLD and never stop them: the owner, or any caller once the gates pass, can still flush.

ArgumentType
min_interval_msu64
min_amountBigUint

deposit​

payable (any token)

Credits the caller's own account. Callable by anyone, smart contracts included (C-11).

No arguments.

depositFor​

payable (any token)

Credits somebody else's account. The payer gets NO rights on the beneficiary's account: it is a payment, not a delegation. The beneficiary guard is evaluated INSIDE run_deposit, as §8.2 step 7, so the step-1 re-entrancy check and the step-2 pause / venue checks are answered first: a re-entrant or paused call must say ERR_REENTRANCY / ERR_PAUSED, never an argument error that looks like client noise.

ArgumentType
beneficiaryAddress

depositAndSubscribe​

payable (any token)

Deposit, then EXACTLY the subscribe logic of §12.2 on the caller's own account — never try_renew (K-17). A failing price, credit, tier or queue check reverts the whole call BEFORE the swap, so a doomed purchase burns little gas of our relayer and the payer keeps the USDC.

ArgumentType
tier_idu32
monthsu8
max_priceu64
referenceoptional<bytes>variadic

Owner-only endpoints​

These revert for every caller but the owner (the deployer wallet — there is no multisig).

setOperator​

owner only

Owner, immediate. Clears ANY pending reporter, due or not: a rotated-out operator leaves nothing behind, and a reporter scheduled by a stolen operator key is dropped even if the owner reacts after the delay.

ArgumentType
operatorAddress

setTreasury​

owner only

Owner. EVERY change, including the first, waits ROLE_CHANGE_NOTICE_MS; one pending slot, last call wins and restarts the notice.

ArgumentType
treasuryAddress

cancelPendingTreasury​

owner only

Owner. A DUE pending treasury is already in force, so it is materialised first and can no longer be cancelled; cancelling it would be an instant treasury change that bypasses the notice.

No arguments.

setRelayerReserve​

owner only

Owner. Published pointer only — the contract never transfers to it; the signer takes its only non-relayer destination from here.

ArgumentType
reserveAddress

unpause​

owner only

No arguments.

unpauseDeposits​

owner only

No arguments.

unpauseSettlement​

owner only

No arguments.

unpauseDistribution​

owner only

No arguments.

unpauseRenewals​

owner only

No arguments.

setTariff​

owner only

ArgumentType
new_tariffu64

cancelPendingTariff​

owner only

A DUE pending value is materialised first and can no longer be cancelled.

No arguments.

setSwapVenue​

owner only

Deep validation by read-only sync calls, reduced to what a plain swap needs: the pair trades exactly {usdc, wegld} and the wrapper unwraps exactly wegld. The pair need NOT be Active (it may be set during a pause). Requires paused || depositsPaused, so a venue switch is always followed by a canary. Token decimals cannot be read on-chain; the deploy script asserts decimals == 6.

ArgumentType
pairAddress
wrapperAddress
usdcTokenIdentifier
wegldTokenIdentifier

setMinDeposit​

owner only

ArgumentType
valueu64

setMaxDeposit​

owner only

0 = unlimited (D-105). Resets the swap window cells, so a new limit starts with a fresh window.

ArgumentType
valueu64

setRateClass​

owner only

Affects only plan blocks written afterwards: blocks snapshot the numbers.

ArgumentType
classu8
max_ru_per_su32
burst_ruu32

setRuSchedule​

owner only

ALWAYS effective after RU_SCHEDULE_NOTICE_MS; one pending slot, last call wins and restarts the notice.

ArgumentType
versionu32
hasharray32<u8>

cancelPendingRuSchedule​

owner only

A DUE pending schedule is materialised first and can no longer be cancelled.

No arguments.

setTier​

owner only

Creates or overwrites a DRAFT. version, status and created_ms supplied by the caller are overwritten.

ArgumentType
tierTierV1

activateTier​

owner only

Draft -> Active. Invariants are re-checked; the rate class must exist because every plan block snapshots its numbers (K-09).

ArgumentType
tier_idu32

setTierStatus​

owner only

ArgumentType
tier_idu32
statusTierStatus
successor_tier_idu32

addCustomBuyer​

owner only

ArgumentType
tier_idu32
addressAddress

removeCustomBuyer​

owner only

ArgumentType
tier_idu32
addressAddress

setSettleCeiling​

owner only

Owner only: the hard ceiling the operator can never reach past.

ArgumentType
ceilingu64

grantCredits​

owner only

ArgumentType
accountAddress
amountu64
reasonGrantReason

grantRu​

owner only

Creates the account when it is missing, so a trial can be granted to an address that has never deposited. Grants are independent of plan blocks and of credits: they are RU, consumed by the backend before cap and PAYG, and they vanish at expiry.

ArgumentType
accountAddress
ruu64
duration_msu64
reasonGrantReason

addRelayers​

owner only

Registers cold rows with weight 0. operator_id and sla_class are the forward hooks of 08 §6.2; v1 accepts only OPERATOR_ID_CORELAYER. The shard is COMPUTED here, never supplied, and smart-contract addresses are refused — a wallet can always receive EGLD, which removes the only path on which a push could bounce.

ArgumentType
operator_idu32
sla_classu8
addressesvariadic<Address>variadic

removeRelayers​

owner only

Frees registry capacity 30 days after retirement. The tombstone and the events remain, so the address stays permanently unregisterable.

ArgumentType
addressesvariadic<Address>variadic

setRelayerMeta​

owner only

Forward hook only (08 §6.2): neither field is read by v1 logic beyond the operator_id == 1 rule.

ArgumentType
addressAddress
operator_idu32
sla_classu8

setMaxRelayerShareBps​

owner only

Owner only. Documented footgun (distribution.md §6.2): a value below 10_000 / n_active makes every activate and re-weight call revert with ERR_SHARE_BOUND until it is raised again. Draining always keeps working, so the fleet can still be stopped during an incident. The change is announced with maxRelayerShareBpsChanged and the value is also readable through getDistributionState (SPEC-DEVIATIONS DEV-21): the owner's off-chain transaction builder recomputes the bound off-chain before the owner signs an activate or a re-weight, and a value that only lives in a raw storage key is invisible to an event-driven mirror.

ArgumentType
bpsu32

emergencyWithdrawPool​

owner only

Owner only, only while the WHOLE contract is paused AND distribution is paused, destination is the treasury and nothing else. In launch mode the pool holds only atto-dust, so this surface is ≈ 0; it becomes relevant only if batching is ever switched on. Disclosed in the docs. Why distributionPaused is required too (SPEC-DEVIATIONS DEV-16): distributeRelayerPool is permissionless and runs under Gate::Open, so paused alone does not stop it. With the launch parameters (min_interval_ms = 0, min_amount = 0) a watcher of the mempool could front-run the rescue with a full permissionless push and make it revert on pool > 0. Requiring distributionPaused means the rescue is only ever reachable from a state in which try_distribute is already a no-op, so the two can never race.

No arguments.