Smart contracts
Every unit of budget lives in a contract you can read. SaTT runs on just two audited Solidity contracts — here is exactly what each one does, who can call it, and the guarantees that keep funds safe.
Single-purpose contracts
There is no central treasury. The factory deploys campaigns; each campaign is its own isolated escrow. One pool can never touch another pool’s money. A separate GigMarketplace handles direct fixed-price deals.
AdpoolFactoryA single, permissionless contract. It deploys every campaign as a low-cost EIP-1167 clone of one shared Adpool implementation, pulls the advertiser’s budget straight into it, and indexes it so the app can list pools. It holds no funds itself.
AdpoolOne clone per campaign, all running the same audited logic. It escrows the reward budget, registers creators, lets the Oracle validate performance, splits the protocol fee, and pays creators on-chain. Its economic terms are set once at creation and can never change.
GigMarketplaceA single escrow for one-to-one work — a creator offer or an advertiser task. Funds lock when hired and release only when the buyer approves; if they go silent the creator self-releases after a review window, and a neutral arbiter resolves any dispute. Same fee, refunds in full.
AdpoolFactory — how funding works
When an advertiser launches a campaign, the factory clones the shared Adpool implementation, initializes the clone, and — in the same transaction — transfers the budget from the advertiser into that pool. It then checks the pool actually received the full amount before recording it, so a deflationary “fee-on-transfer” token that would secretly under-fund the escrow is rejected, not silently broken. Because the clone is created and initialized atomically, there is never a window for anyone to seize an uninitialized pool.
- Canonical SaTT token address (sets the 5% fee tier)
- Ecosystem treasury — receives the ecosystem share of fees
- Buy-back vault — receives the buy-back share of non-SaTT fees
- Default Oracle — the validator used when a campaign doesn’t name its own
Efficient by design
Every campaign is an EIP-1167 minimal-proxy clone of one shared, audited Adpool implementation — not a fresh copy of the whole contract. A clone is just a few hundred bytes that delegate to the same logic, so launching a pool costs a small fraction of a full deployment, while each pool stays a fully isolated escrow.
Two ways to reward creators
The mode is chosen at creation and can never change afterwards.
Oracle-signed (bounty)
The Oracle signs an EIP-712 attestation of a creator’s metrics and exact reward. The creator submits that signature and claims. Each signed claim is single-use — it can never be replayed — and expires after its deadline.
Proportional (performance)
The Oracle SIGNS each creator’s validated metrics; the creator submits them on-chain themselves, so the Oracle never needs gas. The contract still derives every score on-chain from those metrics and the campaign’s immutable weights — so the split stays enforced by code. Once the pool is finalized, each creator pulls their pro-rata share.
The AdPool lifecycle — at a glance
From funding to payout, every step below is enforced by the smart contract — no trust required.
Create & fund
AdvertisercreateAdpool()Fund a reward pool with any ERC-20. The budget is escrowed in a fresh contract and the fee tier locks in: SaTT 5%, any other token 15%.
Apply with your post
CreatorsubmitPromotion()Link your social account once (proves ownership), publish your post, then commit it with a wallet signature.
Oracle validates
OracleThe Oracle fetches the post’s real performance — views, likes and shares.
Bounty pool
Oracle-signed- The Oracle signs your exact reward (EIP-712, single-use, expires).
- You redeem it on-chain — paid instantly, net of the fee.
claimReward()
Performance pool
Proportional- The Oracle signs your metrics; you submit them on-chain yourself (no Oracle gas).
recordMetricsSigned() - Scores freeze at finalize (Oracle anytime; anyone after the end date).
finalize() - Each creator pulls their pro-rata share of the pool.
claim()
End & withdraw
ManagerwithdrawRemaining()After the end date, the manager reclaims the unspent budget. In performance pools only leftover dust is recoverable — every creator’s share stays claimable forever.
Function reference
Every state-changing entry point, who may call it, and what it does.
createAdpool()AdvertiserAdpoolFactoryDeploys a new Adpool and escrows the budget into it in one transaction. Reverts if the token under-funds the pool.
submitPromotion()CreatorAdpoolRegisters the caller’s post in the campaign. Requires the caller’s own EIP-712 signature — you can only enter as yourself.
claimReward()CreatorAdpoolRedeems an Oracle-signed reward. Verifies the signature, enforces single-use and the deadline, splits the fee, and pays the net.
recordMetricsSigned()CreatorAdpoolSubmit your OWN metrics using the Oracle’s EIP-712 signature — so the Oracle only signs and never needs gas. A strictly-increasing nonce blocks replay of a stale attestation. The score is computed on-chain.
recordMetrics()OracleAdpoolOperator/seeding fallback: the Oracle records a creator’s metrics directly (paying gas). The trustless, gasless path is recordMetricsSigned. Blocked once finalized.
finalize()Anyone (after end)AdpoolFreezes metrics and opens claiming. The Oracle may finalize any time; once the end date passes, anyone can — so claims always open even if the Oracle goes silent.
claim()CreatorAdpoolPulls the caller’s pro-rata share after finalization. Shares round down and can never exceed the pool.
withdrawRemaining()ManagerAdpoolAfter the end date, returns the unspent budget. In Proportional mode it can only sweep the unallocated remainder — never a creator’s unclaimed share.
transferManager()ManagerAdpoolProposes a new manager — step 1 of a two-step handover. The role only moves once the proposed address calls acceptManager, so it can never be lost to a typo.
acceptManager()Proposed managerAdpoolStep 2: the proposed address accepts and becomes the manager.
setOracle()ManagerAdpoolProposes a new Oracle. The rotation only takes effect once the proposed address calls acceptOracle, proving the new signing key is live first.
acceptOracle()Proposed oracleAdpoolStep 2: the proposed address accepts and becomes the active Oracle.
Fee model, enforced on-chain
A single fee is taken on each payout — nothing else. The Oracle validates performance but is never a fee recipient.
Why the funds are safe
Non-custodial by design
There is no owner and no admin key. Money can only leave a pool as a validated reward or a post-campaign refund. No one — not us, not the manager, not the Oracle — can move it arbitrarily.
Replay-proof claims
Each Oracle-signed claim is hashed and marked used on redemption, so a signature works exactly once and expires after its deadline.
You can only enter as yourself
Joining a campaign requires an EIP-712 signature from your own wallet, so no one can register another person’s address.
Creator shares are untouchable
In Proportional mode each creator’s share is locked at finalization. The manager’s refund can only reclaim genuine rounding dust — never funds owed to a creator.
Reentrancy-guarded payouts
Every function that moves tokens is protected by OpenZeppelin’s ReentrancyGuard and SafeERC20.
Works with any ERC-20, safely
Funding measures the amount actually received, so deflationary or fee-on-transfer tokens that would under-fund the escrow are rejected up front.
Immutable terms
Token, reward mode, dates, pool size and fee tier are fixed at creation. The rules can’t change under participants mid-campaign.
Audited building blocks
Built on OpenZeppelin 5.x (SafeERC20, EIP712, ECDSA, ReentrancyGuard, Clones) and Solidity 0.8.24 with checked arithmetic.
Clones can’t be hijacked
Each pool is initialized exactly once, atomically, in the transaction that creates it — there is no window to seize an uninitialized clone, and the shared implementation is permanently locked so it can never be used directly.
Every cent is accounted for
On each payout the creator’s net plus the fee split add up to exactly the gross reward — the contract conserves funds precisely, and a payout can never exceed the pool.
Multisig & smart-account ready
Every signature is verified with EIP-1271, so the Oracle can be a multisig or DAO-controlled signer, and creators can act from ERC-4337 smart accounts — not just plain wallets.
Two-step role handover
Manager and Oracle changes are proposed, then accepted by the new address — so control can never be lost to a typo or an unreachable address.
Verification status
The contracts ship with a full automated test suite covering the factory, both reward modes, fee splits, the full lifecycle, and security regressions.
Tests and internal review are not a substitute for a formal third-party audit. An independent audit is recommended before any mainnet deployment that holds real value.
On-chain reference
0x448BEE2d93Be708b54eE6353A7CC35C4933F1156View on BscScan