EVM Contracts (Base L2)
SUDIGITAL's EVM deployment targets Base L2 as the primary chain, with planned expansion to Polygon, Ethereum, and Arbitrum. The codebase includes 8 contracts, 8 shared libraries, and 6 interfaces.
Deployed Contracts
| Contract | Address | Status |
|---|---|---|
| SUDIGITAL Token | 0x4E13A52764aFC8AE4C23C58e67fDe8bf5F6C100b | Verified, Mainnet |
| Gnosis Safe | 0xb0599ce3595Ed3768B08B9B4e7d96AF309a7f49a | 6-of-7, Active |
Deployed: January 25, 2026 | Chain ID: 8453
Supported Chains
| Chain | Chain ID | Type | Status |
|---|---|---|---|
| Base | 8453 | Mainnet | Primary |
| Ethereum | 1 | Mainnet | Planned |
| Arbitrum | 42161 | Mainnet | Planned |
| Optimism | 10 | Mainnet | Planned |
| Polygon | 137 | Mainnet | Planned |
| Sepolia | 11155111 | Testnet | Available |
| Base Sepolia | 84532 | Testnet | Available |
Contract Modules
All contracts use the UUPS proxy pattern (OpenZeppelin Upgradeable) with Solidity ^0.8.28.
SudigitalToken
ERC-20 token with admin controls for the launch period.
Inheritance: Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable
| Constant | Value |
|---|---|
TOTAL_SUPPLY | 1_000_000_000 * 10**6 (1B tokens, 6 decimals) |
| Token Name | "Super Digital" |
| Token Symbol | "SUDIGITAL" |
| Decimals | 6 |
| Function | Access | Description |
|---|---|---|
initialize(owner, treasury) | AUTHORIZED_DEPLOYER only | Mints total supply to treasury |
decimals() | View | Returns 6 |
pause() / unpause() | Owner | Emergency circuit breaker |
freezeAccount(account) | Owner | Freeze individual account transfers |
unfreezeAccount(account) | Owner | Unfreeze account |
isFrozen(account) | View | Check frozen status |
burn(amount) | Any holder | Burn own tokens (inherited) |
burnFrom(account, amount) | Any (with allowance) | Burn with allowance (inherited) |
Events: AccountFrozen(address indexed), AccountUnfrozen(address indexed)
AUTHORIZED_DEPLOYER is immutable, set in constructor, prevents re-initialization. Frozen account check enforced on all transfers via _update() override.
CoreModule (v0.6.6)
Platform configuration, user management, and claim proof processing.
Inheritance: UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeable
| Function | Access | Description |
|---|---|---|
initialize(admin, emergencyContact) | Deployer | Initial setup |
initializePlatformConfig(backendAuthority) | Owner | Set trusted backend signer |
updateBackendAuthority(newAuthority) | Owner | Rotate signing key |
setPlatformActive(isActive) | Owner | Kill switch |
updateAdmin(newAdmin) | Owner | Change admin address |
setEmergencyContact(contact) | Owner | Update emergency contact |
pause() / unpause() | Owner or Admin | Emergency pause |
registerUser() | Any | Create UserProfile on-chain |
processClaim(proof) | Any | Verify claim proof (event-only, no routing) |
getUserProfile(user) | View | Get full user profile |
hasRole(user, role) | View | Check role via bit flags |
getUserLevel(user) | View | Get XP level |
getUserXp(user) | View | Get total XP |
meetsMissionRequirements(user, role, level) | View | Check mission eligibility |
getUserClaimState(user) | View | Get nonce/claim count |
isValidNonce(user, nonce) | View | Check nonce validity |
getBackendAuthority() | View | Get trusted signer address |
isPlatformActive() | View | Check platform status |
Rate Limits (enforced per-user per-day):
| Limit | Value |
|---|---|
| Max missions created per day | 100 |
| Max mission joins per day | 500 |
| Min creation interval | 60 seconds |
StakingModule (v0.6.6)
Token staking with APY rewards and emission controls.
Inheritance: UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuard
| Constant | Value |
|---|---|
LOCK_30_DAYS | 30 days |
LOCK_90_DAYS | 90 days |
LOCK_180_DAYS | 180 days |
LOCK_365_DAYS | 365 days |
APY_FLEXIBLE | 500 (5%) |
APY_30_DAYS | 500 (5%) |
APY_90_DAYS | 800 (8%) |
APY_180_DAYS | 1000 (10%) |
APY_365_DAYS | 1500 (15%, disabled Phase 1) |
DEFAULT_MAX_STAKE_PER_WALLET | 100_000_000_000 (100K tokens) |
DEFAULT_ANNUAL_EMISSION_CAP | 10_000_000_000_000 (10M tokens) |
DEFAULT_MAX_LOCK_DURATION | 180 days |
MIN_STAKE_AMOUNT | 1_000_000 (1 token) |
MIN_HOLDERS_FOR_STAKING | 1111 |
MIN_TVL_FOR_STAKING_USD | 111,111 |
| Function | Access | Description |
|---|---|---|
stake(amount, lockDuration) | Any | Stake tokens with lock |
unstake(amount) | Staker | Withdraw after lock expires |
claimRewards() | Staker | Claim accumulated rewards |
getApyForLockDuration(duration) | View | Get APY tier (caps at maxLockDuration) |
calculateDailyRate(apyBps) | Pure | apyBps / 365 |
getPendingRewards(user) | View | Unclaimed rewards |
getStakeInfo(user) | View | stakedAmount, lockedUntil, pendingRewards, apyBps |
getRemainingAnnualEmission() | View | Remaining emission capacity |
updateStakingConfig(enabled, cap, maxStake, maxLock) | Owner | Full config update |
enableStaking() / disableStaking() | Owner | Convenience toggles |
fundRewardsPool(amount) | Owner | Add tokens to rewards pool |
getRewardsPoolBalance() | View | contract balance - totalStaked |
getStakingConfig() | View | All config values |
Reward formula: rewards = staked * rewardRate * timeElapsed / (BASIS_POINTS * 1 days) -- second-based for precision.
Custom Errors: StillLocked, InsufficientStaked, NoRewardsToClaim, BelowMinimumStake, StakingDisabled, ExceedsMaxStakePerWallet, ExceedsAnnualEmissionCap, LockDurationExceedsMax
VestingModule (v0.6.6)
Team and advisor token vesting with linear release.
Inheritance: UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuard
| Constant | Value |
|---|---|
CLIFF_DURATION | 365 days (12 months) |
VESTING_DURATION | 1460 days (48 months) |
MIN_VESTING_AMOUNT | 1_000_000 (1 token) |
| Function | Access | Description |
|---|---|---|
createVesting(beneficiary, amount, start, cliff, duration) | Owner | Create schedule (uses defaults if 0) |
releaseVested() | Beneficiary | Claim vested tokens |
revokeVesting(beneficiary) | Owner | Revoke unvested tokens |
withdrawUnlocked(amount, recipient) | Owner | Withdraw tokens not locked in vesting |
getReleasableAmount(beneficiary) | View | Claimable now |
getVestedAmount(beneficiary) | View | Total vested so far |
getVestingInfo(beneficiary) | View | Full schedule details |
getBeneficiariesCount() | View | Number of vesting schedules |
Custom Errors: VestingAlreadyExists, VestingNotFound, CliffNotReached, NoTokensToRelease, VestingAlreadyRevoked, InvalidAmount, InvalidDuration, InsufficientBalance, ZeroAddress
MissionModule (v0.6.6)
Mission escrow, winner recording, and reward distribution with rate limiting and circuit breaker.
Inheritance: UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuard
| Function | Access | Description |
|---|---|---|
depositEscrow(missionId, paymentToken, amount, expiresAt) | Any (payable) | Fund mission escrow (ETH or ERC-20) |
recordWinner(proof) | Backend | Record verified winner, awards XP (75+500) |
batchRecordWinners(proofs[]) | Backend | Batch record (max 100) |
claimReward(missionId) | Winner | Claim with 80/15/5 split |
refundEscrow(missionId) | Creator/Admin | Refund if cancelled/expired |
setHolderShares(missionId, holders[], shares[]) | Owner | Set NFT holder reward shares |
batchSetHolderShares(missionId, holders[], shares[]) | Owner | Batch set (max 100) |
claimHolderReward(missionId) | Holder | Claim proportional holder reward |
markRefundable(missionId) | Owner | Allow refund on escrow |
withdrawPending() | Any | Pull-payment fallback for failed ETH |
setEconomyModule(address) | Owner | Set economy module for XP awards |
setEcosystemFund(address) | Owner | Set ecosystem fund recipient |
setDepositRateLimit(...) | Owner | Configure deposit rate limits |
setClaimRateLimit(...) | Owner | Configure claim rate limits |
resetCircuitBreaker() | Owner | Manual circuit breaker reset |
Reward Distribution (enforced in claimReward):
| Pool | BPS | % |
|---|---|---|
| Winner | 8,000 | 80% |
| Holder Pool | 1,500 | 15% |
| Ecosystem Fund | 500 | 5% |
Rate Limits:
| Action | Max/Hour | Max/Day | Cooldown |
|---|---|---|---|
| Deposit | 10 | 50 | 10s |
| Claim | 20 | 100 | 5s |
Supports both ETH and ERC-20 payments -- pass address(0) as paymentToken for native ETH.
NftModule (v1.2.0)
ERC-1155 NFTs with fractional ownership and SUDIGITAL token payment.
Inheritance: ERC1155Upgradeable, UUPSUpgradeable, OwnableUpgradeable, ReentrancyGuard (no PausableUpgradeable -- checks coreModule.isPlatformActive() instead)
| Constant | Value |
|---|---|
MAX_EDITION | 6,666 |
BASIS_POINTS | 10,000 |
FOUNDER_SHARE_BPS | 100 (1%) |
CREATOR_SHARE_BPS | 100 (1%) |
PLATFORM_SHARE_BPS | 9,800 (98%) |
BURN_SHARE_OF_PLATFORM_BPS | 2,500 (25% of platform = ~24.5% total) |
| Function | Access | Description |
|---|---|---|
mintNft(proof, maxShares) | Any (with proof) | Mint NFT with SUDIGITAL token payment |
validateNftHolder(nftId, holder, minShares) | View | Check holder status |
migrateHolderShares(nftId, holders[]) | Owner | Migrate share data to ERC-1155 |
updatePlatformWallet(address) | Owner | Update platform wallet |
updateCreatorWallet(address) | Owner | Update creator wallet |
setURI(newuri) | Owner | Update metadata URI |
uri(tokenId) | View | Metadata URI with {id} replaced |
getNftMetadata(nftId) | View | Full metadata |
getHolderShare(nftId, holder) | View | Share info |
canMintShare(nftId) | View | Check availability |
remainingShares(nftId) | View | Shares left |
getTotalBurned() | View | Cumulative burn amount |
Token IDs: Edition number directly (1-6666). The getTokenId(role, nftId) function ignores the role parameter and returns uint256(nftId).
First mint: 25% of price burned, 75% to platform. Creates NftMetadata with founder set. Subsequent mint: 1% founder + 1% creator + ~73.5% platform + ~24.5% burned. Payment: SUDIGITAL ERC-20 token only.
EconomyModule (v0.6.6)
XP system, leveling, and daily check-ins.
Inheritance: UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeable
| Function | Access | Description |
|---|---|---|
initializeXp(user) | Owner or Authorized | Create XP account |
awardXp(user, baseXp) | Owner or Authorized | Award XP (auto-inits if needed) |
checkIn() | Any | Daily check-in (20 XP + streak bonuses) |
updateMissionStats(user, completed, won, rewardAmount) | Owner or Authorized | Update mission counters |
setAuthorizedCaller(caller, authorized) | Owner | Authorize contracts to call |
getXpAccount(user) | View | Full XP data |
getUserLevel(user) | View | Current level |
getUserXp(user) | View | Total XP |
getUserStreak(user) | View | Consecutive login days |
getXpThreshold(level) | Pure | XP needed for level |
getLevelName(level) | Pure | Level name string |
getLevelMultiplier(level) | Pure | Multiplier in BPS |
Check-in rewards: 20 XP base, 150 XP at 7-day streak, 1,000 XP at 30-day streak. Streak: 1-day window + 1-hour grace period. Breaks if >25 hours since last login. Storage gap: 48 slots (other modules use 50).
AirdropModule (v1.0.0)
Pull-based airdrop distribution with custom reentrancy guard.
Inheritance: UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeable (custom reentrancy, NOT OZ ReentrancyGuard)
| Function | Access | Description |
|---|---|---|
createAirdropEscrow(tokenAddress, amount) | Owner | Create and fund escrow |
refillEscrow(airdropId, amount) | Owner | Add more tokens |
claimAirdrop(proof) | Any (with proof) | Claim airdrop with signed proof |
deactivateAirdrop(airdropId) | Owner | Pause airdrop |
activateAirdrop(airdropId) | Owner | Resume airdrop |
closeAirdropEscrow(airdropId) | Owner | Close and return remaining |
setBackendAuthority(newAuthority) | Owner | Update signer |
Shared Library Details
Roles.sol
enum Role {
None, // 0
Memer, // 1
Worker, // 2
Player, // 3
Trader, // 4
Builder, // 5
Owner, // 6
Admin // 7
}Roles use bit flags for efficient multi-role storage: toBitFlag(role) returns 1 << (uint8(role) - 1).
TokenAllocation.sol (6 decimals)
| Allocation | BPS | Tokens |
|---|---|---|
| Ecosystem | 4,000 (40%) | 400_000_000 * 10**6 |
| Treasury | 2,500 (25%) | 250_000_000 * 10**6 |
| Team | 1,500 (15%) | 150_000_000 * 10**6 |
| Sale | 1,000 (10%) | 100_000_000 * 10**6 |
| Liquidity | 1,500 (15%) | 150_000_000 * 10**6 |
Also defines: MAX_STAKE_PER_WALLET, ANNUAL_EMISSION_CAP, DAILY_EMISSION_CAP, MAX_LOCK_DURATION_PHASE1.
MissionTypes.sol
| Enum | Values |
|---|---|
| MissionStatus | Created(0), Active(1), Completed(2), Cancelled(3), Failed(4), Expired(5) |
| MissionType | Task(0), Challenge(1), Quiz(2), Tournament(3), Prediction(4), Social(5) |
| MissionDifficulty | Beginner(0), Intermediate(1), Advanced(2), Expert(3), Master(4) |
Error Codes
All errors are string constants in Errors.sol (e.g., string public constant UNAUTHORIZED = "6110"). Key ranges:
| Range | Module | Example Codes |
|---|---|---|
| 6100-6199 | Core | 6110 Unauthorized, 6120 ProofExpired, 6130 PlatformNotActive |
| 6200-6299 | Economy | 6211 InvalidXpAmount, 6230 AlreadyCheckedInToday |
| 6300-6499 | NFT | 6312 MaxSharesReached, 6331 InsufficientPayment |
| 6500-6799 | Mission | 6500 EscrowNotActive, 6560 CircuitBreakerOpen |
| 6800-6899 | Token | 6810 SupplyExceeded, 6840 TokenPaused |
| 7000-7099 | Staking | 7004 StakingDisabled, 7005 ExceedsMaxStake |
| 7200-7299 | Vesting | 7201 CliffNotPassed, 7202 VestingRevoked |
| 7300-7399 | Roles | 7301 RoleAlreadyOwned, 7305 MaxNftsReached |
| 7400-7499 | Security | 7401 RateLimitHourly, 7410 CircuitBreaker |
Related
- Contract Architecture -- proxy pattern, claim proofs
- Solana Programs -- Anchor equivalent
- Security -- multisig, rate limiting
- Integration Guide -- TypeScript SDK