Affiliate pool litepaper

The GM affiliate alpha pool

Technical description of the affiliate pool as deployed on Bittensor finney mainnet on 6 October 2026: subnet 28 (GM), EVM chain id 964, pool contract 0xb2152F0aF2ad35Cc2a707F30087E249789F9fAc1.

Abstract

GM directs a share of its subnet's alpha emissions to an on-chain pool and pays that alpha to affiliates whose referrals pay for GM. A Solidity contract behind an ERC-1967 (UUPS) proxy on Subtensor EVM holds the alpha as stake owned by the proxy's mapped coldkey. A dedicated miner UID on subnet 28 earns the pool's share of emissions.

Referred revenue is reported to the contract in rounds. When a round closes, the contract prices that revenue in alpha at a submitted closing price, caps the allocation at a configured fraction of the revenue, and applies one allocation rate to every affiliate in the round. Each allocation is held for a period that depends on how the customer paid, then transferred as alpha stake to the affiliate's coldkey. Alpha a round does not allocate stays in the pool for later rounds.

The governing rule: an affiliate earns alpha against qualifying money customers paid, up to a configured cap valued at the round's closing price. On mainnet the cap is 10,000 basis points: at most $1 of alpha, valued at close, per $1 of qualifying revenue. When a round's referred revenue exceeds what the pool can fund at the cap, every affiliate in that round is paid pro rata at the same lower rate. Rounds close daily.

1. Components

ComponentDescription
CustomerA saygm.com account holder who buys prepaid credit by card, TAO, alpha or USDC
AffiliateAnyone with a Bittensor coldkey who signs in on saygm.com and shares referral links
Pool minerUID 157 on subnet 28, hotkey 5CfaJ817vpL7PzBwijLJd2PLe86a2synojuP1z81CJA52TXj
Pool contractThe proxy above; holds the alpha, keeps the round and bucket ledger, does all allocation arithmetic and executes payouts
Affiliate serviceGM's off-chain service; applies attribution and eligibility rules, reports revenue, closes rounds and pays
OperatorThe affiliate service's signing account, 0x4F8BA786924B93281d44E00C8Cf1a09174037229; the only account that can report, close, reduce and pay
AdminGM's administrative account, 0xb9EE3886106B39367D45a711A0a69F015bdFd73f; configures, pauses, resumes and upgrades
Alpha and revenue flowSubnet 28 emissions go to the pool miner, UID 157, whose pool and payout hotkey auto-stakes them as stake owned by the pool contract's coldkey. The pool contract, an ERC-1967 proxy, pays affiliate coldkeys with payBatch. Separately, customers pay on saygm.com; the affiliate service reports that revenue to the contract with reportBatch and closes rounds with closeRound and a closing price, signing as the operator. The admin pauses, resumes, upgrades and configures the contract.ALPHAREVENUE DATAAdminpause · resumeupgrade · configSubnet 28emissionsPool minerUID 157pool + payouthotkeyPool contractERC-1967 proxystake owned bycontract coldkeypayBatchAffiliatescoldkeysCustomerpays on saygm.comAffiliate servicesigns as operatorreportBatchcloseRound + price
Alpha and revenue flow

2. Funding

2.1 Emissions to the pool miner

Subnet 28 validator weights give the pool miner the miner emission that remains after GM's miner payouts. The weights identify the pool by hotkey and map it to its current UID each epoch. The amount varies with GM's traffic and miner payouts, so pool income varies from epoch to epoch.

The runtime credits the pool miner's incentive as stake owned by the contract's coldkey, 5GJqZYDskw7DGFxNmwfVNq3j27H5WJZbwwJJo4F4VcBXfGtF. On mainnet the pool hotkey is also the payout hotkey and the auto-stake destination, so emissions accrue directly in the position that pays affiliates. The contract's coldkey is separate from the subnet-owner coldkey.

2.2 Measuring inflow

The contract measures inflow from chain state at each close. Let

  • C = the contract's alpha stake summed over its tracked hotkeys (at most 4), read at close;
  • C_prev = the same sum at the previous close;
  • P = alpha debited by payouts since the previous close, measured inside each payout as the source balance before minus after.

The round's new inflow is

D=C−Cprev+P.D = C - C_{prev} + P.

D includes miner incentive, validator dividends and any stake sent to a tracked position. A negative D beyond a rounding tolerance of a few rao stops the close. A close also stops if the chain reports locked stake on the contract's positions or if the subnet's registration generation has changed.

3. Custody

The contract holds the pool's alpha as stake owned by the proxy's mapped coldkey, and its code is the spending rule. Alpha leaves custody only through payBatch, which pays closed, matured, unresolved buckets their remaining entitlements. Balances, round records and events are public, and anyone can recompute allocations from the reported data.

3.1 Deployment

After the implementation was deployed, one atomic bootstrap transaction (block 9,222,764) deployed the proxy, initialized it with its roles, subnet binding, payout hotkey and configuration, funded it with TAO for registration, registered the pool miner under the contract's coldkey with a capped burn, set auto-stake, verified ownership, and proposed the admin. The admin accepted in the next block. The pool then stayed paused until the admin resumed it (block 9,223,735). A failure at any step would have reverted the whole bootstrap.

3.2 Recovery from deregistration

Deregistration stops emission income but leaves the contract's coldkey, stake and liabilities in place. The admin pauses the pool, registers a hotkey under the same contract with a capped burn, moves stake between tracked positions if needed, and resumes. Rounds, liabilities and the payout hotkey carry over.

4. Rounds

Rounds are numbered sequentially and are time-based, independent of Bittensor epochs.

  1. Open. A round opens when the previous round closes. Round 1 opened at deployment.
  2. Report. The operator submits reportBatch calls of up to 64 items. Each item adds referred revenue to a bucket or subtracts a same-round adjustment. Batches are globally sequenced. A replay of the last batch with the same payload hash is a no-op. Stale, conflicting or skipped sequences fail.
  3. Close. At least 24 hours after open, the operator calls closeRound with the expected round id, the alpha/USD price and its timestamp. The close reconciles funding, computes the envelope, freezes the round and opens the next round in one transaction.
  4. Hold. Each bucket waits its hold period, counted from the actual close.
  5. Pay. The operator pays matured buckets in batches.

A late close lengthens the round. Configuration changes take effect at the next round open; a round always settles under the configuration it opened with.

A bucket is the ledger entry for one (round, affiliate coldkey, bucket id). The bucket id selects the hold period:

BucketCustomer payment methodHold
0TAO, alpha and USDC, including x4027 days
1Card120 days
Round lifecycleRound N is open while the operator submits reportBatch calls. At least 24 hours after it opened, closeRound sets the price, computes the envelope and freezes round N, and opens round N+1 in the same transaction. Counted from that close, bucket 0 (TAO, alpha and USDC payments) holds for 7 days and bucket 1 (card payments) holds for 120 days; each bucket then matures and is paid by payBatch. The hold bars are drawn to scale in days after close; the round itself is not.reportBatch callsRound N open · at least 24 hcloseRoundprice · envelope · freezeRound N+1 open, same transactionBucket 0 · TAO, alpha, USDC7-day hold → matured → payBatchBucket 1 · card120-day holdmatured → payBatch07306090120days after close
Round lifecycle

5. Allocation

5.1 Notation and units

SymbolMeaningUnit
BAlpha available to the round at closerao (10⁻⁹ α)
RThe round's total qualifying revenuenano-USD
rOne bucket's revenuenano-USD
xRevenue later cancelled from a closed bucketnano-USD
pClosing price, USD per whole alphanano-USD per α
cMaximum reward ratiobasis points, 0 to 10,000
EThe round's reward enveloperao

Amounts are uint64 with checked arithmetic and uint256 intermediates. Division rounds down; overflow reverts.

5.2 Available alpha

L is the alpha still reserved by earlier rounds: unpaid entitlements plus rounding dust awaiting release. At close,

B=C−L.B = C - L.

With S the surplus carried from the previous close and paid the entitlements settled since then, the contract also checks the reconciliation identity

B=S+D+released+dust+paid−PB = S + D + released + dust + paid - P

and stops the close if the two disagree or if C < L.

5.3 The envelope

Ecap=⌊R⋅c⋅109p⋅10,000⌋,E=min⁡(B, Ecap),E=0 when R=0.E_{cap} = \left\lfloor \frac{R \cdot c \cdot 10^9}{p \cdot 10{,}000} \right\rfloor,\qquad E = \min(B,\ E_{cap}),\qquad E = 0 \text{ when } R = 0.

The round's allocation rate, in dollars of alpha at the closing price per dollar of revenue, is

ρ=E⋅pR⋅109≤c10,000.\rho = \frac{E \cdot p}{R \cdot 10^9} \le \frac{c}{10{,}000}.

When B ≥ E_cap the round pays the cap and B − E carries forward. When B < E_cap the whole pool is allocated and the rate falls below the cap.

5.4 Entitlements

A bucket with revenue r and cancelled revenue x, in a round with R > 0, is entitled to

entitle(r,x)=⌊(r−x)⋅ER⌋.\text{entitle}(r, x) = \left\lfloor \frac{(r - x)\cdot E}{R} \right\rfloor.

Every bucket in a round shares the rate E/R. Rounding down leaves fewer rao than there are positive-revenue buckets; that dust stays reserved until every bucket in the round is resolved, then returns to the pool.

5.5 The cap holds per bucket

For any bucket in a round with R > 0:

entitle(r,0)⋅p109  ≤  r⋅E⋅pR⋅109  ≤  r⋅c10,000  ≤  r.\frac{\text{entitle}(r, 0) \cdot p}{10^9} \;\le\; \frac{r \cdot E \cdot p}{R \cdot 10^9} \;\le\; \frac{r \cdot c}{10{,}000} \;\le\; r.

At the closing price, alpha allocated against a dollar of referred revenue is worth at most c/10,000 dollars. Its later dollar value moves with the market.

5.6 Worked example

Illustrative values: c = 10,000 bps, closing price p = $2.50.

Funding. At the previous close the contract held C_prev = 3,000 α, with L = 2,400 α reserved and S = 600 α carried. Since then payouts debited P = 700 α and emissions added D = 600 α.

  • C = 3,000 − 700 + 600 = 2,900 α
  • L = 2,400 − 700 = 1,700 α
  • B = 2,900 − 1,700 = 1,200 α

Revenue. R = $2,000 across three buckets: affiliate A card $1,200, affiliate A crypto $300, affiliate B card $500.

Envelope. E_cap = 2,000 × 1.00 / 2.50 = 800 α; E = min(1,200, 800) = 800 α; 400 α carries forward. The rate is $1.00 of alpha per $1.

Bucketr · E / RAlpha
A, card1,200 × 800 / 2,000480 α
A, crypto300 × 800 / 2,000120 α
B, card500 × 800 / 2,000200 α

A refund. $100 of A's card bucket is refunded before payout. The bucket's entitlement becomes 1,100 × 800 / 2,000 = 440 α, and 40 α returns to the pool at the next close.

Oversubscribed. Had R been $5,000, E_cap = 2,000 α > B, so E = 1,200 α and the rate is $0.60 of alpha per $1. A $1,000 bucket receives 240 α.

Envelope: cap-bound and pool-bound roundsBars drawn to scale in alpha, from the worked example. Cap-bound round: 1,200 alpha available and a cap of 800 alpha, so the envelope is 800 alpha, 400 alpha carries forward, and the rate is $1.00 of alpha per $1. Oversubscribed round: 1,200 alpha available and a cap of 2,000 alpha, so the envelope is the whole 1,200 alpha, nothing carries forward, and the rate is $0.60 of alpha per $1.Cap-bound · R = $2,000B available1,200 αEcap800 αE allocated800 α, 400 α carries forwardRate $1.00 of alpha per $1, the capOversubscribed · R = $5,000B available1,200 αEcap2,000 αE allocated1,200 α, 0 α carries forwardRate $0.60 of alpha per $1, below the cap05001,0001,5002,000alpha
Envelope: cap-bound and pool-bound rounds

6. The closing price

The operator submits the price with each close as nano-USD per whole alpha plus the quote's timestamp, derived from public market data for TAO/USD and alpha/TAO. The contract rejects a zero price, a timestamp later than the block, and a quote older than maxPriceAgeSecs (3,600 seconds on mainnet). The price and timestamp are stored in the round record and emitted in RoundClosed, so anyone can compare them with the market at that block.

7. Holds and payouts

A bucket matures at

tmature=tclose+hold_days[bucket]×86,400 s.t_{mature} = t_{close} + \text{hold\_days}[\text{bucket}] \times 86{,}400 \text{ s}.

The hold lets refunds and disputes arrive before alpha moves. Maturity is the earliest release time; the service pays once the payment records it depends on are reconciled.

payBatch takes up to 32 buckets and 16 recipients. For each bucket it records the payment and lowers L; then, grouped by recipient, it calls the staking precompile's transferStake from the payout position to the recipient's coldkey on the same subnet and hotkey, measuring the debit and delivery from balances before and after. A batch is atomic, and each bucket is payable once.

Affiliates receive alpha stake under their own coldkey on the pool hotkey. They never call the contract or submit a claim; GM pays the transaction fees.

Each transfer must meet the runtime's minimum transfer, which is TAO-valued and converted to alpha at the current price. A reward below the payout threshold stays reserved for its owner and is combined with the same affiliate's later rewards until the total can be transferred.

8. Refunds and disputes

WhenCallEffect
The payment's round is openreportBatch adjustmentSubtracts the amount from the bucket's revenue and from R
The round has closed and the bucket is unpaidreduceRewardsBatchRaises the bucket's cancelled revenue x and releases entitle(r, x_old) − entitle(r, x_new) to the pool

Closed-round reductions set the new cumulative x with the bucket's expected revision, so partial refunds never compound rounding. Each change requires x_old < x_new ≤ r; at x = r the bucket is cancelled. Other buckets, and the round's price and rate, are unchanged. A card dispute cancels the payment's unpaid reward in full when it opens. Each reduction records a reason: refund, dispute, linked account or other.

A paid bucket is final.

Bucket statesA bucket is open while its round is open and takes same-round adjustments through reportBatch. closeRound moves it to closed and holding. reduceRewardsBatch can lower its entitlement while holding or matured, until payout. When the hold elapses it is matured, and payBatch moves it to paid, which is final. A closed, unpaid bucket whose cancelled revenue x reaches its revenue r is cancelled.reportBatchsame-round adjustmentreduceRewardsBatchlowers the entitlementreduceRewardsBatchuntil payoutOpenround opencloseRoundClosedholdinghold endsMaturedpayablepayBatchPaidfinalCancelledx = rx reaches rx reaches r
Bucket states

9. Eligibility and attribution

These rules are applied by the affiliate service; the contract sees their results.

  • Attribution is fixed at signup. Affiliates share saygm.com/r/<code> links. The first referral code a visitor arrives with is kept for up to 30 days and attached to the account they create; the referrer is then fixed for that account.
  • New accounts only. Accounts created before 6 October 2026 do not qualify.
  • A 30-day earning window. A referred account's first successful top-up starts it. Every successful top-up in the following 30 days counts.
  • Revenue is the amount paid. Rewards count successful payments, not credit usage or promotional balances.
  • One reward per customer. Accounts linked by a shared payment method are treated as one customer; only the earliest-created account in a linked group can earn rewards. A link found later cancels the unpaid rewards of the later account.
  • One payout address. All of an affiliate's rewards go to the coldkey they signed in with.

10. Roles and administration

Operator: reportBatch, closeRound, reduceRewardsBatch, payBatch, pruneRound, pause.

Admin: queueConfig, rotateOperator, pause, resume, proposeAdmin, upgradeToAndCall, registerCustodyHotkey, setAutoStake, moveCustodyStake, trackCustodyHotkey, untrackCustodyHotkey. Pending admin: acceptAdmin.

  • Pause. The operator or the admin can pause; pause stops every operator write. Only the admin can resume. Custody changes require a paused pool.
  • Admin transfer is two-step: proposeAdmin, then acceptAdmin from the proposed account.
  • Upgrade. upgradeToAndCall is admin-only. An upgrade leaves the pool paused; the admin resumes separately. The proxy address, custody coldkey and accounting persist across upgrades.
  • Configuration. queueConfig stores a version that activates at the next round open, within these bounds: minimum round ≥ 1 second; 1 to 8 buckets; holds of 0 to 180 days; c from 0 to 10,000 bps; price age ≥ 1 second.

The contract emits events for configuration, round open and close, reports, reductions, payments, transfers, dust, pruning, role changes, pause and resume, upgrades and custody changes.

11. Privacy

Affiliate coldkeys, amounts and times are public on chain, with round and payout records. Customer identity is not.

  • Each reported payment appears on chain only as an opaque 32-byte reference, an HMAC of GM's payment id under a key held by the service, with the affiliate's coldkey, bucket, amount and time.
  • Emails, API keys, card details, wallet addresses and account identifiers stay off chain.
  • Affiliates sign in with their coldkey through Taostats, signing a message with the coldkey; the signed-in coldkey is the payout address.
  • Affiliate pages show referred revenue, refunds, rewards and payouts, with customers shown only as pseudonymous references.

12. Trust model

The contract enforces arithmetic, sequencing, funding, holds and payout rules. Some inputs come from GM:

  • Reported revenue. The contract cannot verify that a reported payment happened or that attribution is correct. Every report is an on-chain event and auditable after the fact.
  • The closing price. The contract enforces freshness and rejects a zero price; the price itself is submitted by the operator and published with each close.
  • Upgrades. The admin can upgrade the implementation without a delay. Upgrades are on-chain events and leave the pool paused until a separate resume.
  • Emission income. Pool income depends on the pool miner's registration and subnet 28's validator weights.
  • Market price. Close fixes the alpha amount. Its dollar value afterwards moves with the market.
  • Finality. Paid alpha is not recovered; a refund after payout is a cost to the pool.

Appendix A. Mainnet configuration

SettingValue
ChainBittensor finney, EVM chain id 964
Subnet28 (GM)
Pool contract (proxy)0xb2152F0aF2ad35Cc2a707F30087E249789F9fAc1
Implementation0xa8ffccd468ab57fbb52f2bfdb56fa70226dc3efa
Contract coldkey5GJqZYDskw7DGFxNmwfVNq3j27H5WJZbwwJJo4F4VcBXfGtF
Pool and payout hotkey5CfaJ817vpL7PzBwijLJd2PLe86a2synojuP1z81CJA52TXj (UID 157)
Admin0xb9EE3886106B39367D45a711A0a69F015bdFd73f
Operator0x4F8BA786924B93281d44E00C8Cf1a09174037229
Deployed6 October 2026, block 9,222,764
Minimum round duration86,400 s (daily)
Hold, bucket 0 (TAO, alpha, USDC)7 days
Hold, bucket 1 (card)120 days
maxRewardBps (c)10,000
maxPriceAgeSecs3,600
Earning window30 days from first top-up
Referral link capture30 days

Per-call limits: 8 buckets, 4 tracked hotkeys, 64 report items per batch, 64 reductions per batch, 32 buckets and 16 recipients per payout batch.

Appendix B. Contract interface

Operator: reportBatch, closeRound, reduceRewardsBatch, payBatch, pruneRound, pause. Admin: queueConfig, rotateOperator, pause, resume, proposeAdmin, upgradeToAndCall, registerCustodyHotkey, setAutoStake, moveCustodyStake, trackCustodyHotkey, untrackCustodyHotkey. Pending admin: acceptAdmin. Read: getRound, getOpenRound, getRoundAffiliates, getAffiliateRound, getBucket, getConfig, getActiveConfigVersion, getPendingConfigVersion, getAdminState, getReportCursor, getCustodyState, getSubnetBinding, getRegistrationState, codeStorageVersion, reportHashVersion, reportDomain, getLimits, selfColdkey, stakeOf, fundingPreview, reportPayloadHash.