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
| Component | Description |
|---|---|
| Customer | A saygm.com account holder who buys prepaid credit by card, TAO, alpha or USDC |
| Affiliate | Anyone with a Bittensor coldkey who signs in on saygm.com and shares referral links |
| Pool miner | UID 157 on subnet 28, hotkey 5CfaJ817vpL7PzBwijLJd2PLe86a2synojuP1z81CJA52TXj |
| Pool contract | The proxy above; holds the alpha, keeps the round and bucket ledger, does all allocation arithmetic and executes payouts |
| Affiliate service | GM's off-chain service; applies attribution and eligibility rules, reports revenue, closes rounds and pays |
| Operator | The affiliate service's signing account, 0x4F8BA786924B93281d44E00C8Cf1a09174037229; the only account that can report, close, reduce and pay |
| Admin | GM's administrative account, 0xb9EE3886106B39367D45a711A0a69F015bdFd73f; configures, pauses, resumes and upgrades |
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 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.
- Open. A round opens when the previous round closes. Round 1 opened at deployment.
- Report. The operator submits
reportBatchcalls 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. - Close. At least 24 hours after open, the operator calls
closeRoundwith 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. - Hold. Each bucket waits its hold period, counted from the actual close.
- 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:
| Bucket | Customer payment method | Hold |
|---|---|---|
| 0 | TAO, alpha and USDC, including x402 | 7 days |
| 1 | Card | 120 days |
5. Allocation
5.1 Notation and units
| Symbol | Meaning | Unit |
|---|---|---|
B | Alpha available to the round at close | rao (10⁻⁹ α) |
R | The round's total qualifying revenue | nano-USD |
r | One bucket's revenue | nano-USD |
x | Revenue later cancelled from a closed bucket | nano-USD |
p | Closing price, USD per whole alpha | nano-USD per α |
c | Maximum reward ratio | basis points, 0 to 10,000 |
E | The round's reward envelope | rao |
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,
With S the surplus carried from the previous close and paid the entitlements settled since
then, the contract also checks the reconciliation identity
and stops the close if the two disagree or if C < L.
5.3 The envelope
The round's allocation rate, in dollars of alpha at the closing price per dollar of revenue, is
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
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:
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.
| Bucket | r · E / R | Alpha |
|---|---|---|
| A, card | 1,200 × 800 / 2,000 | 480 α |
| A, crypto | 300 × 800 / 2,000 | 120 α |
| B, card | 500 × 800 / 2,000 | 200 α |
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 α.
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
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
| When | Call | Effect |
|---|---|---|
| The payment's round is open | reportBatch adjustment | Subtracts the amount from the bucket's revenue and from R |
| The round has closed and the bucket is unpaid | reduceRewardsBatch | Raises 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.
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, thenacceptAdminfrom the proposed account. - Upgrade.
upgradeToAndCallis admin-only. An upgrade leaves the pool paused; the admin resumes separately. The proxy address, custody coldkey and accounting persist across upgrades. - Configuration.
queueConfigstores 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;cfrom 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
| Setting | Value |
|---|---|
| Chain | Bittensor finney, EVM chain id 964 |
| Subnet | 28 (GM) |
| Pool contract (proxy) | 0xb2152F0aF2ad35Cc2a707F30087E249789F9fAc1 |
| Implementation | 0xa8ffccd468ab57fbb52f2bfdb56fa70226dc3efa |
| Contract coldkey | 5GJqZYDskw7DGFxNmwfVNq3j27H5WJZbwwJJo4F4VcBXfGtF |
| Pool and payout hotkey | 5CfaJ817vpL7PzBwijLJd2PLe86a2synojuP1z81CJA52TXj (UID 157) |
| Admin | 0xb9EE3886106B39367D45a711A0a69F015bdFd73f |
| Operator | 0x4F8BA786924B93281d44E00C8Cf1a09174037229 |
| Deployed | 6 October 2026, block 9,222,764 |
| Minimum round duration | 86,400 s (daily) |
| Hold, bucket 0 (TAO, alpha, USDC) | 7 days |
| Hold, bucket 1 (card) | 120 days |
maxRewardBps (c) | 10,000 |
maxPriceAgeSecs | 3,600 |
| Earning window | 30 days from first top-up |
| Referral link capture | 30 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.