BeginBlock
The exchange BeginBlocker runs at the start of every block in our defined order as the last module.
1. Process Hourly Fundings
Check the first to receive funding payments market. If the first market is not yet due to receive fundings (funding timestamp not reached), skip all fundings.
Otherwise go through each market one by one:
Skip market if funding timestamp is not yet reached.
Compute funding as
twap + hourlyInterestRate
where $\mathrm{twap = \frac{cumulativePrice}{timeInterval * 24}}$ with $\mathrm{timeInterval = lastTimestamp - startingTimestamp}$. ThecumulativePrice
is previously calculated with every trade as the time weighted difference between VWAP and mark price: $\mathrm{\frac{VWAP - markPrice}{markPrice} * timeElapsed}$.Cap funding if required to the maximum defined by
HourlyFundingRateCap
.Set next funding timestamp.
Emit
EventPerpetualMarketFundingUpdate
.
2. Process Markets Scheduled to Settle
For each market in the list of markets to settle:
Settle market with zero closing fee and current mark price.
Run socialized loss. This will calculate the total amount of funds missing in all of the market and then reduce the payout proportionally for each profitable position. For example a market with a total amount of 100 USDT missing funds and 10 profitable positions with identical quantity would result in a payout reduction of 10 USDT for each of the positions.
All positions are forcibly closed.
Delete from storage.
3. Process Matured Expiry Future Markets
For each time expiry market, iterate through starting with first to expire:
If market is premature, stop iteration.
If market is disabled, delete market from storage and go to next market.
Get cumulative price for the market from oracle.
If market is starting maturation, store
startingCumulativePrice
for market.If market is matured, calculate the settlement price as $\mathrm{twap = (currentCumulativePrice - startingCumulativePrice) / twapWindow}$ and add to list of markets to be settled.
Settle all matured markets with defined closing fee and settlement price. The procedure is identical to the previous process of settling (see above). Note that the socialized loss is an optional step. In the regular case a market will not require any socialized loss.
Delete any settled markets from storage.
4. Process Trading Rewards
Check if the current trading rewards campaign is finished.
If the campaign is finished, distribute reward tokens to eligible traders.
Compute the available reward for each reward denom as
min(campaignRewardTokens, communityPoolRewardTokens)
Get the trader rewards based on the trading share from the respective trader calculated as
accountPoints * totalReward / totalTradingRewards
.Send reward tokens from community pool to trader.
Reset total and all account trading reward points.
Delete the current campaign ending timestamp.
If a new campaign is launched, set the next current campaign ending timestamp as
CurrentCampaignStartTimestamp + CampaignDurationSeconds
.If no current campaign is ongoing and no new campaigns are launched, delete campaign info, market qualifications and market multipliers from storage.
5. Process Fee Discount Buckets
If the oldest bucket's end timestamp is older than the
block.timestamp - bucketCount * bucketDuration
:Prune the oldest bucket
Iterate over all
bucketStartTimestamp + account → FeesPaidAmount
:Subtract the
FeesPaidAmount
from each account'stotalPastBucketFeesPaidAmount
Delete the account's
account → {tier, TTL timestamp}
. Note that this technically isn't necessary for correctness since we check the TTL timestamps in the Endblocker but is a state pruning strategy.
Update the
CurrBucketStartTimestamp ← CurrBucketStartTimestamp + BucketDuration
.
Last updated