Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Sonic is the highest-performing EVM L1, combining speed, incentives, and world-class infrastructure for DeFi. The chain provides 400,000 TPS and sub-second finality.
Developers and users on Sonic are supported by several incentive programs, including:
Sonic delivers exceptional performance, enabling developers to scale their applications without limits while ensuring smooth user experiences.
400,000 Transactions per Second
Sub-Second Finality
EVM Compatible
Solidity/Vyper Support
The of Sonic is S, which is used for transaction fees, staking, running validators, and participating in governance.
Furthermore, the provides developers and users with seamless access to vast liquidity through a secure bridge connected to Ethereum. With a unique fail-safe mechanism, it ensures user assets are protected in all circumstances.
Developers earn 90% of the network fees their apps generate.
Up to 200 million S to onboard apps to Sonic and support new ventures.
~200 million S to incentivize users of Sonic via an innovative points program.
Sonic is the highest-performing EVM layer-1 blockchain, combining speed, incentives, and world-class infrastructure, powering the next generation of DeFi applications. The chain provides 400,000 TPS and sub-second finality.
By combining a novel consensus mechanism with full EVM compatibility, Sonic delivers unparalleled speed, security, and scalability. The is Sonic's native token, used for paying transaction fees, staking, running validators, and participating in governance.
Key Features:
Sub-Second Finality Transactions are confirmed and irreversible in under a second.
Full EVM Compatibility Deploy your existing Ethereum app on Sonic without changing your code.
Fee Monetization Developers earn 90% of the network fees generated by their applications.
Network name: Sonic
RPC URL: https://rpc.soniclabs.com
Explorer URL: https://sonicscan.org
Chain ID: 146
Currency symbol: S
The S token is the native token of Sonic. It has multiple roles within the network, such as paying for transaction fees, staking, running validators, and participating in governance.
— Staking — Supply and Tokenomics — Institutional Expansion — Airdrop — Ongoing Funding — Block Rewards — Token Burn — Validator Rewards — Ecosystem Vault
You can help secure the network and earn rewards by staking your S tokens.
Visit .
Connect your wallet.
Choose a reputable validator and delegate your stake.
Staking your S involves a 14-day waiting period if you choose to withdraw. When staking your S, choose a reputable validator carefully. If your validator is penalized for misconduct or errors in their setup, it could impact your delegated S stake as well.
The current total supply of S is approximately 3.8 billion. As decided by multiple governance proposals, the following adjustments have been or will gradually be integrated into the tokenomics of S.
A approved the issuance of $50M in S for the pursuit of an ETF, $100M in S for the pursuit of a Nasdaq DAT, and 150M S tokens for the newly established Sonic USA entity, as part of our institutional expansion into the U.S. capital markets.
The first issuance of 472,372,662.8 S . This covered the full allocation for our Nasdaq DAT and Sonic USA entity. An additional $50 million in S may also be issued to support our pursuit of an S ETF.
The following transactions provide transparency into how the issued funds have been used to date, mainly involving .
to old SonicStrategy DAT Multisig
to new SonicStrategy DAT Multisig for validator setup
to new SonicStrategy DAT Multisig from the old SonicStrategy DAT Multisig
Importantly, if a Nasdaq DAT is not achieved during SonicStrategy’s pursuit, all funds will be returned to the Sonic Foundation to be leveraged for an alternative DAT or burned.
190.5 million S will be issued in phases exclusively used for the . The airdrop features an that rewards active participation and gradually reduces the total supply of S tokens.
The first issuance of 89,778,181.9 S occurred on and .
To fund ongoing growth and expansion, the Sonic network could to:
Increase S adoption and global presence
Grow the team and scale operations to drive increased adoption
Implement robust marketing initiatives and DeFi onboarding campaigns
To fund this program, 47,625,000 tokens will be issued annually for six years, starting six months after Sonic's mainnet launch. Issued tokens will be sent to . The first issuance of 47,625,000 S .
However, to guard against inflation, the network will burn newly issued tokens not used during the year, ensuring that 100% of all newly issued tokens from this initiative are allocated toward network growth rather than being held by the treasury for later use.
For example, if Sonic Labs uses only 5,000,000 tokens in the first year, the network will burn the remaining 42,625,000 tokens.
were migrated Fantom Opera to Sonic. As validators and stakers moved to Sonic, Opera's block rewards were reduced to zero, and the saved funds are used to reward Sonic validators. The Sonic Foundation will maintain Opera validators for now.
To achieve a 3.5% APR for Sonic without causing further inflation in the first four years, we're reallocating the remaining block rewards from Opera to Sonic, comprising around 70 million tokens per year, which will be distributed as validator rewards over the first four years, avoiding the need to issue new S tokens during this period for block rewards.
As a result, Opera's APR dropped to zero upon Sonic's launch. To preserve value and avoid new inflationary rewards at Sonic's inception, we will not issue new tokens for block rewards during the initial four years, as stated. After that period, S block rewards will resume by issuing new tokens at a rate of 1.75% per year to reward validators.
We have two burn mechanisms in place that will decrease the emission of new S tokens.
To help secure the Sonic network by running a validator and staking a certain amount of S, you can earn block rewards as well as transaction fees paid by users on Sonic.
The target reward rate for validators on Sonic is 3.5% when 50% of the network is staked. The network issues tokens each epoch to provide this, except during Sonic's first four years when rewards stem from block rewards migrated from Opera, .
The reward rate adjusts proportionally, e.g. if all S tokens are staked, the annual reward is 1.75%. Conversely, if only 25% of S tokens are staked, the annual reward is 7%.
Network fees are generated when users pay gas to interact with the network. Validators earn a percentage of these fees, which are distributed equally among all staked S tokens. For a detailed breakdown of how much a validator earns from gas fees, .
Users
Developers


Sonic offers developers robust infrastructure with 400,000 transactions per second and sub-second finality, ensuring your apps are both fast and scalable.
With full EVM compatibility and support for Solidity and Vyper, Sonic seamlessly integrates with common developer tools such as Chainlink, Safe, Pyth, Alchemy, and more. Additionally, Sonic provides the incentives, such as Fee Monetization, necessary to innovate and thrive in the ecosystem.
Test your contracts on the Sonic testnet first, then deploy to the mainnet when ready. Dive in and explore how you can leverage Sonic's powerful features to bring your ideas to life.
The Sonic chain is secured using a proof-of-stake (PoS) mechanism.
In PoS on Sonic, validators must lock their S (Sonic's native token); if they act maliciously in the network, they lose their tokens. Validators are incentivized to act in the network's best interest as their own funds are at stake. Since validators do not need to perform computations, this approach is a much more energy-efficient alternative to proof-of-work for achieving resistance to Sybil attacks.
A Sybil attack is an attack where a malicious actor runs a large number of validators to allow them an unsafe amount of influence over the network. PoS makes it costly to set up these validators and allows the network to punish validators for malicious behavior, increasing the costs of attacks.
Sonic requires nodes to lock up at least 500,000 S to validate transactions and produce blocks.
Users who choose not to wait for the full 270-day maturation period for 75% of their airdrop will lose a portion of their S tokens, which will be burned.
From the 47,625,000 S tokens issued annually in the first six years of Sonic to fund growth, the network will burn any of the tokens not used during the year.
The Sonic chain provides developers with exceptional scalability and storage capabilities while delivering a fast and seamless user experience.
Sonic achieves 10,000 transactions per second with sub-second finality for immediate, irreversible transactions. There is zero risk of rollbacks or reorganizations, making every transaction final and tamper-proof. Sonic's cutting-edge storage system ensures efficient data management.
Learn more about the Sonic technology stack:
If a contract is already registered under a different app in Fee Monetization, your registration attempt will fail with ContractAlreadyRegistered(contract, projectID).
If you believe the contract rightfully belongs to you, file a dispute using the steps below.
Visit the Fee Monetization dashboard and connect your admin wallet
Click My FeeM in the menu and then Create Dispute
Enter your dispute contact email address and the contracts you wish to dispute
Click Submit and pay the 50 S fee, which will be refunded if the dispute is accepted
Once submitted, we will process your dispute as quickly as possible and notify you via email. If resolved in your favor, the dispute fee is refunded and the disputed contracts are moved to your app.
Nodes are interconnected devices, usually software run on servers, that maintain the Sonic network by storing a full or partial copy of the chain, validating transactions, and ensuring consensus to keep the system secure and decentralized.
Visit the pages below to learn how to deploy archive and validator nodes on Sonic.
At the software level, deploying to Sonic is the same as deploying to any other EVM network.
The only difference is which network you connect to. Use as the connection endpoint for the Sonic testnet or for the mainnet.
For the Sonic testnet, you can use the to obtain an initial amount of S to execute transactions on the testnet.
Here are example configurations for Hardhat to deploy on the Sonic mainnet or testnet:
To deploy, execute npx hardhat run scripts/deploy.js --network sonic.
Sonic offers developers two distinct networks to build and deploy their apps. First, the serves as a dedicated environment where you can rigorously test your smart contract code and deployments, ensuring everything functions correctly using faucet tokens.
Once your contracts are thoroughly vetted on the testnet, you can confidently deploy your live apps to the Sonic mainnet, the production environment where end users will interact with your apps.
The following are the network details:
Network name: Sonic
RPC URL:
Alternative fee payments enable users to interact with an app without holding the network’s primary token (S) to cover gas fees. Instead, gas costs are paid using an alternative method, such as ERC-20 tokens (e.g. stablecoins) or even off-chain settlement. This removes the requirement for users to maintain a balance of the native token.
Sonic uses database storage to store its world state, which includes account information, virtual machine bytecode, smart contract storage, etc. This database has a feature called live pruning, which removes historical data automatically, reducing storage needs for validators as the blockchain grows.
Previously, pruning required validator nodes to go offline, risking financial and operational issues for them. Now, validators can use live pruning without going offline, ensuring continuous operation and saving on disk space and costs by discarding historical data in real-time.
Live pruning works by splitting the database into two types: LiveDB and ArchiveDB. The LiveDB contains the world state of the current block only, whereas the ArchiveDB contains the world states of all historical blocks. Validators use only LiveDB, while have both LiveDB and ArchiveDB to handle historical data requests through the RPC interface.
Sonic's database storage uses efficient tree-like or hierarchical structures, which simplifies data retrieval. Importantly, it still provides cryptographic signatures for a world state and archive capabilities using an incremental version of a prefix algorithm. Additionally, it utilizes a native disk format instead of storing the world state indirectly through key-value stores like LevelDB or PebbleDB.
You can build apps on top of Sonic's staking system, such as liquid staking tokens or vaults. All staking operations are managed by the SFC (Special Fee Contract).
SFC Address:
0xFC00FACE00000000000000000000000000000000
Key Functions:
Sonic is fully compatible with the Ethereum Virtual Machine (EVM). Any smart contract that runs on Ethereum can be deployed on Sonic without modification.
Supported Languages Solidity and Vyper
Supported EIPs
Sonic supports Ethereum's Cancun hard fork features, including PUSH0 opcode (EIP-3855), with the exception of EIP-4844 data blobs. All transactions must have a Chain ID (EIP-155 is enforced).
delegate(validatorID)undelegate(validatorID, wrID, amount): Begin the withdrawal process.
withdraw(validatorID, wrID): Claim unlocked stake after the withdrawal period.
pendingRewards(delegator, validatorID): Check claimable rewards.
claimRewards(validatorID): Claim pending rewards.
Constants
Economic parameters like withdrawal period and reward rates are available by calling the constsAddress() on the SFC to get the ConstantsManager contract address.
See the API & SDK Reference for the full SFC ABI.
Note on PUSH0 Opcode: Sonic's EVM supports the PUSH0 opcode. RPC tests that fail with eth_call are often missing the required block parameter (e.g., "latest"). A correctly formatted call like eth_call with params [{"to": null, "data": "0x5f"}, "latest"] will succeed.
25% of your allocation is claimable now, with the remaining 75% vesting over nine months as an NFT.
You can trade this NFT on the official Airdrop Order Book by Paintswap.
There are two ways users can receive S from Gems.
Tokenized Gems If you used apps that tokenized Gems for their users, head to MySonic to deposit your tokenized Gems and claim wS. 50% is available now, with the rest vesting over 3 months. No minimum claim.
Non-Tokenized Gems If you used apps that did not tokenize Gems, we will send S directly to them.
They will handle distribution to their users, with 50% available to apps immediately and the rest vesting over 3 months via LlamaPay. No minimum claim.

Please note that the Sonic testnet is a testing playground designed to showcase technology capabilities. The data stored on the network might eventually be deleted, with or without notice.
require("@nomicfoundation/hardhat-toolbox");
// Replace this private key with your Sonic account private key
const SONIC_PRIVATE_KEY = "YOUR SONIC TEST ACCOUNT PRIVATE KEY";
module.exports = {
solidity: "0.8.26",
networks: {
sonic: {
url: "https://rpc.soniclabs.com",
accounts: [SONIC_PRIVATE_KEY]
}
}
};require("@nomicfoundation/hardhat-toolbox");
// Replace this private key with your Sonic account private key
const SONIC_PRIVATE_KEY = "YOUR SONIC TEST ACCOUNT PRIVATE KEY";
module.exports = {
solidity: "0.8.26",
networks: {
sonic: {
url: "https://rpc.testnet.soniclabs.com",
accounts: [SONIC_PRIVATE_KEY]
}
}
};Within each UserOperation, the user specifies a paymaster contract. This paymaster (not the sender) pays the bundler for the gas used by the UserOperation.
The paymaster’s primary function is to determine whether a UserOperation qualifies for sponsorship, typically by checking if the operation interacts with the subsidized app. This verification is non-trivial, since users can deploy arbitrary smart account implementations. To prevent abuse, the paymaster must:
Inspect the UserOperation’s calldata to confirm it targets the sponsored contract(s).
Verify that the user’s account is running a pre-approved smart account implementation.
An example paymaster for sponsoring a single-contract app might look like this:
contract MyPaymaster is IPaymaster {
function validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external view override returns (bytes memory context, uint256 validationData) {
if (msg.sender != address(entryPoint)) {
revert InvalidEntryPoint();
}
// check if the sender use a whitelisted account implementation
if (userOp.sender.codehash != keccak256(abi.encodePacked(bytes3(0xef0100), allowedSmartAccountImpl))) {
revert InvalidAccountCodeHash();
}
// check if userOp.callData targets the whitelisted contract
checkUserOpCallData(userOp.callData);
// check if userOp.gasFees are within limits
checkUserOpGasFees(userOp.gasFees);
return ("", _packValidationData(false, 0, 0)); // accept paying gas
}
}An alternative fee payment system can be built on the same ERC-4337 account abstraction principles used in the fee subsidies mechanism.
As with subsidies, users submit UserOperations to a bundler rather than sending transactions directly on-chain. The paymaster contract specified in the UserOperation determines whether to cover the gas cost, typically by interacting with the user’s credit source, most commonly an ERC-20 token.
The paymaster:
Verifies the user has sufficient available credit to cover the estimated gas cost.
Deducts or reserves the required amount from the user’s credit source.
For ERC-20 token payments, the user must first approve an allowance for the paymaster. When assessing a UserOperation, the paymaster transfers the maximum token amount needed to cover gas fees. Once execution is complete and the actual gas usage is known, the paymaster refunds any unused portion to the user.
For popular stablecoins (e.g. USDC), a paymaster is already provided by the token issuer. For other ERC-20 tokens, developers can implement a custom paymaster by extending, for example, PaymasterERC20 from OpenZeppelin community-contracts:
A guide for creating similar paymasters can be found in the OpenZeppelin documentation.
import "@openzeppelin/community-contracts/account/paymaster/PaymasterERC20.sol";
contract MyERC20Paymaster is PaymasterERC20, Ownable {
function _fetchDetails(
PackedUserOperation calldata userOp,
bytes32 /* userOpHash */
) internal view virtual override returns (uint256 validationData, IERC20 token, uint256 tokenPrice) {
// oversimplified example - real-live paymaster should check liveness and sanity of the price
uint256 price = oracle.getLatestTokenPrice();
return (
ERC4337Utils.SIG_VALIDATION_SUCCESS,
USDC,
price
);
}
function _authorizeWithdraw() internal virtual override onlyOwner {}
}Explorer URL: https://sonicscan.org
Explorer API: https://api.etherscan.io/v2/api?chainid=146
Chain ID: 146
Currency symbol: S
Network name: Sonic Testnet
RPC URL: https://rpc.testnet.soniclabs.com
Explorer URL: https://testnet.sonicscan.org
Explorer API: https://api.etherscan.io/v2/api?chainid=14601
Chain ID: 14601
Currency symbol: S
Faucet:
Network name: Sonic Blaze Testnet
RPC URL: https://rpc.blaze.soniclabs.com
Explorer URL: https://blaze.soniclabs.com/
Chain ID: 57054
Currency symbol: S
Faucet:
The Sonic Blaze testnet (2.0) will be depreciated soon.
With the Ethereum Pectra upgrade supported in Sonic release 2.1, the network gains full compatibility with ERC-4337, a transformative framework originally introduced on Ethereum.
ERC-4337 replaces traditional externally owned accounts (EOAs) with smart contract wallets that have programmable authorization logic. This enables advanced features such as:
Social Recovery Restore access with help from trusted guardians.
Multi-Signature Security Require multiple approvals before executing transactions.
Spending Limits Enforce daily/weekly caps on outgoing funds.
Token-Based Gas Payments Pay fees in ERC-20 tokens instead of the native token.
Unlike protocol-level changes, ERC-4337 operates entirely on top of the blockchain. No network hard fork is required, making it immediately compatible with Sonic post-Pectra. It works through a specialized flow involving UserOperations, an alternative mempool, bundlers, and optional paymasters for gas fee handling.
This upgrade fundamentally improves the Sonic user experience, unlocking customizable, secure, and user-friendly wallets without sacrificing decentralization or performance.
Smart Wallet An ERC-4337 smart wallet extends the functionality of a standard EOA by delegating control to a smart contract. This enables transaction batching, gas sponsorship, and custom permission logic while still functioning like a traditional wallet.
EntryPoint The EntryPoint contract is the core of ERC-4337. It validates signatures, nonces, and logical rules defined by each wallet. It can also enforce custom conditions such as balance checks, restricted contract calls, or app-specific rules.
UserOperation
A UserOperation is a generalized transaction format for ERC-4337. It contains standard fields like sender, recipient, calldata, maxFeePerGas, maxPriorityFeePerGas, signature, and nonce, along with additional fields such as callGasLimit, verificationGasLimit, and paymasterAndData to support advanced execution logic.
Bundler A bundler collects UserOperations from the alternative mempool, simulates them for validity, and packages them into a single transaction sent to the EntryPoint. Bundlers may also forward standard transactions to a full node for normal blockchain processing.
Paymaster A paymaster is a smart contract that sponsors gas fees on behalf of users, allowing them to transact without holding the network’s native token. During validation, the paymaster checks if the operation qualifies for sponsorship and covers the gas cost. To prevent abuse, paymasters stake collateral with the EntryPoint and must maintain a sufficient deposit.
Customize transaction authorization logic with smart contract wallets.
Let users interact with an app without paying gas themselves.
Monetize app usage via increased gas consumption.
Accept ERC-20 tokens or off-chain settlement for gas fees.
Sonic Labs has partnered with HackQuest to offer a learning track for anyone who is eager to learn Solidity on Sonic, whether they are a beginner or advanced. Start learning now.
Upon completing the course outlined below, graduates will receive a Sonic Developer Certificate.
Account abstraction enables users to customize how transactions from their account are authorized. This flexibility supports alternative signing methods, multi-signature requirements, and account recovery mechanisms. Examples include:
Alternative Signing Methods Passkey, YubiKey, or TouchID to sign transactions directly in the browser without extensions like MetaMask.
Multi-Signature Wallets Requiring multiple signatures before a transaction can be executed.
Social Recovery Allowing a group of trusted contacts to override or replace the account’s controlling key.
ERC-4337 introduces a framework where user wallets are implemented as smart contracts. This allows the wallet’s transaction authorization logic to be fully customizable. Transactions are sent as UserOperations and processed according to the smart account’s rules.
EIP-7702 extends this flexibility by allowing a regular externally owned account (EOA) with a standard ECDSA private key to deploy a smart contract directly into its account. Once a smart account implementation is deployed, the user can send transactions in two ways:
Regular Transactions Signed with their private key.
UserOperations Authorized according to the custom logic defined in their smart account.
Example Authorization Logic Options
Passkey / YubiKey / TouchID []
Signs UserOperations directly in the browser, without extensions like MetaMask.
Currently a research project—experimental and not recommended for production.
Google OAuth JWT signing []
The FeeM Vault is a multisig operated by Sonic Labs. It accumulates 90% of transaction fees generated by core token contracts on Sonic:
wS
USDC
USDT
EURC
WETH
WBTC
Funds in the FeeM Vault will be strategically deployed to strengthen the Sonic ecosystem, provide targeted support where apps need it most, and enhance asset incentives.
The tokens that generate the revenue for the FeeM Vault will also shape how it is spent. Apps that integrate and optimize for the tokens above will be first in line to benefit.
Key areas of deployment include:
The FeeM Vault is designed to compound growth across Sonic apps. As activity around key tokens increases, the Vault fills, and a self-reinforcing flywheel begins to spin:
More usage of key tokens increases the transaction fees redirected to the FeeM Vault.
More revenue in the FeeM Vault means more funding available for apps on Sonic.
More funding for apps leads to more integrations and incentives involving key tokens, attracting more users.
More users drive more activity and usage of those same tokens.
Sonic has undergone extensive security audits across its core components to ensure the highest level of security for our users and developers.
The Sonic Gateway is our native bridge between Ethereum and Sonic.
The FTM to S bridge enables users to upgrade their FTM on Fantom Opera to S on Sonic.
The SFC manages staking and validator operations on Sonic.
Sonic supports a range of popular wallets, both for users and institutions. Use the network information below to add Sonic to your wallet.
Network name: Sonic
RPC URL: https://rpc.soniclabs.com
Explorer URL: https://sonicscan.org
Chain ID: 146
Currency symbol: S
The Sonic Labs Innovator Fund offers up to 200,000,000 S from the Sonic Foundation treasury to expedite the immediate adoption of apps to the Sonic chain and support new innovative ventures.
Funding from the Innovator Fund is being used to secure the best infrastructure and applications for Sonic, ensuring builders have the tools and capabilities to thrive within today’s ever-challenging marketplace.
We’re actively engaging with dozens of apps across the industry and top-tier infrastructure providers across on-chain tooling, compliance, native assets, cross-chain technology, wallets, indexes, strategic Web2 partnerships, and more.
To do so, we’ll work closely with strategic angel investors such as (Curve), (Aave), (Compound), (Gauntlet), and (FRAX), as well as our venture partners , , and .
The Sonic & Sodas program empowers our community to host developer-focused networking events around the world, funded by Sonic Labs.
Think of Sonic & Sodas events as grassroots gatherings where collaboration, networking, and innovation thrive, all within the Sonic ecosystem. You host the event, and we provide the funding. Our aim is to cultivate local communities, particularly in tech hubs and around major conferences.
The process for organizing a Sonic & Sodas event is detailed below.
Got questions? .
The active network parameter set can be obtained directly from an RPC interface:
The second season of the airdrop and Kaito program are ending on November 1, 2025. Future incentive programs will be announced at a later stage.
Game Gems mark the beginning of a new chapter on Sonic, where blockchain games are not just part of the ecosystem, but central to its growth.
Just like DeFi apps earn , eligible games on Sonic earn Game Gems, unlocking a share of the S token airdrop. Similar to the existing Sonic Gems, these allocations are designed to be distributed to players, helping bootstrap in-game activity and drive lasting engagement.
Signs UserOperations in the browser without MetaMask.
Requires publishing the user’s email and account name as part of the JWT on-chain.
Relies on an on-chain oracle to provide Google’s current public key (JWKS, rotated every 48 hours).
Gas-expensive; suitable for social recovery but not optimal for everyday use.
n-of-m signature requirements via Web3Auth
Supports conventional social login (e.g. Google account plus additional factors).
Depends on the trustworthiness of the third-party service (Web3Auth servers).
Social Recovery (ERC-7093)
Allows the account owner to designate “guardians” who can replace the owner key.
ERC-7093 is currently a proposal without a reference implementation.
For EIP-7702 smart accounts, the ability to send regular transactions signed with the account’s private key remains unaffected.
Once your proposal is approved, start planning. Choose a time that works best — whether it’s breakfast, lunch, or dinner. Select a venue that’s easily accessible and fosters a welcoming atmosphere for networking.
The growth score uses a transaction-weighted Quick Ratio to evaluate a game’s player dynamics. Specifically, it measures how many new and returning players a game attracts compared to how many users it’s losing or failing to retain.
This formula is designed to reward both new and established games fairly. To prevent manipulation, the score is capped, and scores cannot fall below zero. The metric is dynamic, with flexibility to adjust time windows, weighting, and inputs as new games join the program.
The activity score tracks relative player engagement across the ecosystem. It rewards games that command a larger share of total active users in the Game Gems program.
This helps ensure the reward distribution reflects real-time network activity and user interest.
Each game (denoted as g) will receive an overall score, calculated as a weighted blend of the growth and activity scores. These weights (wg and wa) are chosen by Sonic Labs to reflect strategic goals and may evolve over time.
And the cycle continues.
Liquidity Incentives Directing FeeM Vault revenue toward strategic pools to deepen liquidity and reduce borrowing costs.
Protocol Integrations Funding integrations of core assets like USDC.e, WETH, and wS into apps.

curl -sX POST -H "Content-type: application/json" -d '{"id":1,"jsonrpc":"2.0","method":"eth_getRules","params": ["latest"]}' https://rpc.sonic.soniclabs.com | jq{
"jsonrpc": "2.0",
"id": 1,
"result": {
"Name": "sonic",
"NetworkID": 146,
"Dag": {
"MaxParents": 12,
"MaxFreeParents": 6,
"MaxExtraData": 128
},
"Emitter": {
"Interval": 200000000,
"StallThreshold": 30000000000,
"StalledInterval": 60000000000
},
"Epochs": {
"MaxEpochGas": 15000000000,
"MaxEpochDuration": 600000000000
},
"Blocks": {
"MaxBlockGas": 5000000000,
"MaxEmptyBlockSkipPeriod": 4000000000
},
"Economy": {
"BlockMissedSlack": 50,
"Gas": {
"MaxEventGas": 30000000,
"EventGas": 28000,
"ParentGas": 2400,
"ExtraDataGas": 25,
"BlockVotesBaseGas": 1024,
"BlockVoteGas": 512,
"EpochVoteGas": 1536,
"MisbehaviourProofGas": 71536
},
"MinGasPrice": 0,
"MinBaseFee": 50000000000,
"ShortGasPower": {
"AllocPerSec": 1000000000,
"MaxAllocPeriod": 5000000000,
"StartupAllocPeriod": 1000000000,
"MinStartupGas": 560000
},
"LongGasPower": {
"AllocPerSec": 1000000000,
"MaxAllocPeriod": 5000000000,
"StartupAllocPeriod": 1000000000,
"MinStartupGas": 560000
}
},
"Upgrades": {
"Berlin": true,
"London": true,
"Llr": false,
"Sonic": true,
"Allegro": true,
"Brio": false,
"SingleProposerBlockFormation": false,
"GasSubsidies": true
}
}
}Consensus in a decentralized system is not just a process but a cornerstone of the system. Its mechanism guarantees a consistent and secure blockchain among all participants and ensures the system's integrity and reliability. Consensus ensures that transactions are consistently and securely validated and added to the blockchain.
It's a critical element for effectively thwarting attempts by malicious actors to manipulate the network or its data. Sonic uses Asynchronous Byzantine Fault Tolerance in combination with directed acyclic graphs to achieve consensus.
Practical Byzantine Fault Tolerance (PBFT) is a consensus mechanism designed to enable decentralized systems to function correctly in the presence of malicious or faulty nodes. It is named after the Byzantine generals’ problem, which is an idea that illustrates the difficulties of achieving consensus in a decentralized system when some of the participants may be acting in bad faith.
In a PBFT system, nodes in a network communicate with each other to reach a consensus on the system's state, even when malicious actors are involved. To achieve this, they send messages back and forth that contain information about the system's state and the actions they propose.
Each node verifies the message it receives, and if it determines the message is valid, it sends a message to all the other nodes to indicate its agreement. In the context of cryptocurrencies, the message with which all nodes must agree is the blockchain, a ledger that stores a history of transactions.
Before the invention of cryptocurrencies, the major flaw with PBFT systems was their susceptibility to Sybil attacks. If an attacker controlled a sufficient number of nodes, they could control the entire system; there needed to be a deterrent to launch many nodes. Bitcoin first solved this problem with proof-of-work, forcing nodes to invest considerable energy to partake in the consensus.
Since then, many new solutions have been developed, such as , which forces nodes to deposit tokens with monetary value, which Sonic uses.
Hence, Practical Byzantine Fault Tolerance (PBFT) is a mechanism to achieve consensus. It forms a functioning decentralized system when coupled with proof-of-work or proof-of-stake to deter participants from messing with the network. However, Sonic has decided to innovate on this mechanism by using Asynchronous Byzantine Fault Tolerance.
With Asynchronous Byzantine Fault Tolerance (ABFT), nodes can reach consensus independently and are not required to exchange final blocks sequentially to confirm transactions. At the same time, they exchange blocks, which is required to achieve consensus, and this is done asynchronously. Each node verifies transactions independently and is not required to incorporate blocks created by other miners or validators in sequential order.
This is opposed to PBFT systems, such as Bitcoin, in which the majority of nodes must agree to a block before it becomes final, which they must then sequentially order into their blockchain record. This slows down the network during high traffic; more on this in the consensus mechanism section further below.
Now that we have a basic understanding of Byzantine fault tolerance, let’s delve into the second part of Sonic’s consensus mechanism, directed acyclic graphs.
A graph is a non-linear data structure used to represent objects, called vertices, and the connections between them, called edges. A directed graph dictates that all its edges, the connections between objects, only flow in a certain direction. An acyclic graph does not contain any cycles, which makes it impossible to follow a sequence of edges and return to the starting point. As such, a directed acyclic graph (DAG) only flows in a certain direction and never repeats or cycles.
The diagram below is an example of a directed acyclic graph. Each oval is a vertex, and the lines connecting them are edges. The vertices only connect in one direction, downwards, and never repeat.
In our consensus algorithm, an event containing transactions is represented by a vertex in a DAG, and edges represent the relationships between the events. The edges may represent the dependencies between events indicating the order in which they were added to the DAG.
Events can be created and added to the DAG concurrently. The blocks do not need to be added in a specific order, which enables the system to achieve faster transaction times. It is not limited by the requirement to incorporate blocks sequentially, as is the case with many of the biggest blockchains currently available.
Sonic uses a proof-of-stake, DAG-based, ABFT consensus mechanism. In this mechanism, each validator has its own local block DAG and batches incoming transactions into event blocks, which they add to their DAG as vertices — each event block is a vertex in the validator’s DAG that is full of transactions.
Before creating a new event block, a validator must first validate all transactions in its current event block and part of the ones it has received from other nodes; these are the event blocks it has received during the asynchronous exchange of event blocks explained in the section above. The new event block then is communicated with other nodes through the same asynchronous event communication.
During this communication, nodes share their own event blocks, and the ones they received from other nodes, with other validators that incorporate them in their own local DAGs. Consequently, this spreads all information through the network. The process is asynchronous as the event blocks shared between validators are not required to be sequential.
Unlike most blockchains, this DAG-based approach does not force validators to work on the current block that is being produced, which places restrictions on transaction speed and finality. Validators are free to create their own event blocks that contain transactions and share these with other validators on the network asynchronously, creating a non-linear record of transactions. This increases transaction speed and efficiency.
As an event block is sent and propagated across validators, it becomes a root event block once the majority of validators have received and agreed upon it. This root event block will eventually be ordered and included in the main chain, which is a blockchain that contains the final consensus among all event blocks that have become root event blocks.
Every validator stores and updates a copy of the main chain, which provides quick access to previous transaction history to process new event blocks more efficiently. As such, Sonic's consensus mechanism combines a DAG-based approach that allows validators to confirm transactions asynchronously, which greatly increases speed, with a final blockchain that orders and stores all final transactions immutably and indefinitely.
Currently, the process of submitting a transaction and having it added to the Sonic main chain through the consensus mechanism takes approximately 1-2 seconds. This involves the following steps:
A user submits a transaction
A validator node batches the transaction into a new event block
The event block becomes a root event block once the majority of nodes have received it
The root event block is ordered and finalized into the main chain as a block
When a user explores Sonic through a , they view the final blocks on the Sonic main chain. Event block generation and exchange in validators' DAGs is an internal process only and is not visible to end users.
To better understand the technical aspects of Sonic's consensus mechanism, review the paper on Fantom Opera's consensus mechanism, as Sonic's design is a continuation of it:
.
Verifying your smart contract makes its source code publicly visible and auditable on the block explorer, creating transparency and trust. Here are the recommended methods to verify contracts on the and the .
— — — — —
The most streamlined way to verify contracts is using Hardhat with hardhat-toolbox:
This guide describes the steps for upgrading a Sonic mainnet node to the latest 2.1.2 version, which introduces the to the Sonic network.
Once upgraded, your nodes will continue to operate on the current mainnet until the full transition. The upgrade is backward compatible, meaning you can upgrade now without any interruption.
The guide covers the following steps:
The following version history documents the Sonic client (the node software that powers the Sonic mainnet) including its virtual machine, database storage, and consensus mechanism.
Gas Power
Each validator has a "gas power" budget that refills over time, based on their stake. This prevents any single validator from congesting the network. If a validator runs out of gas power, they may temporarily be unable to emit events containing large transactions, resulting in a Not enough gas power to emit event warning.
While eth_estimateGas is fully supported, its estimates can sometimes be inaccurate for complex transactions whose gas usage depends on the current on-chain state.
The Problem
The state of the chain can change between the time of gas estimation and the time of transaction execution. For contracts like a UniswapV3Pool, a change in the pool's state can alter the execution path and, consequently, the gas required.
The Symptom
This can lead to random out of gas transaction reversions.
The Solution For transactions with state-dependent gas costs, it is best practice to add a buffer (e.g., 20-30%) to the estimated gas limit to ensure successful execution. Unused gas is refunded.
Hex Conversion Issues Ensure proper hex to decimal conversion (0xcce416600 = 55,000,000,000 wei, not 54,816,600,000)
Use Suggested Values Don't use raw block base fee; use RPC-suggested values that include buffers
Minimum Tip Is Fine Don't increase priority fee unless you specifically need priority during high load
Check Transaction Type Ensure you're setting the correct fields for Type 1 vs Type 2 transactions



Install Hardhat toolbox:
Configure hardhat.config.js:
Store your SonicScan API key in a .env file:
Verify your contract:
For automated deployments, you can verify contracts programmatically in your deployment scripts:
If automated methods fail, you can verify manually through the explorer interface:
Go to the Sonic explorer (or the testnet explorer)
Navigate to your contract address
Click the Contract tab and Verify & Publish
Fill in the verification details:
Contract address
Compiler type (single file recommended)
Compiler version (must match deployment)
Open-source license
Optimization settings (if used during deployment)
If your contract has constructor arguments:
Generate ABI-encoded arguments at e.g.
Paste them in the Constructor Arguments field
Complete the captcha and submit
For contracts with complex dependencies that fail standard verification:
Install Hardhat flattener:
Flatten your contract:
Clean up the flattened file:
Keep only one SPDX license identifier
Keep only one pragma statement
Use this file for manual verification
Common verification issues to check:
Compiler version must match deployment exactly
Optimization settings must match deployment
Constructor arguments must be correctly ABI-encoded
Library addresses must be provided if used
Source code must match deployed bytecode exactly
Flattened files should not have duplicate SPDX/pragma statements
Update your operating system.
Verify the version and upgrade the Golang version to v1.24 or newer as needed.
Obtain the new Sonic release v2.1.2 source code from GitHub.
Build the source code into a binary client.
Update the active Sonic binary to the new one, and verify the proper version is used.
Stop the currently running client gracefully.
Verify the client is not running.
Validators, pay attention to your node being recognized as by the network before you proceed.
Start the node with the new Sonic client version.
Verify the new version is up and running.
Building the Sonic client binary requires the essential software compilation tools and the Go language version 1.24 or newer to be available. Please refer to your Linux distribution manuals to obtain the development tools on your system.
Make sure you use a clean copy of the Sonic client source code from the official GitHub repository. A modified client may lead to an inconsistent state, which will disconnect your node from the network.
Build the Sonic client:
Download the latest Sonic client source code from the official GitHub repository.
git clone https://github.com/0xsoniclabs/sonic.git
Switch to the most recent Sonic release.
cd sonic && git fetch --tags && git checkout -b v2.1.2 tags/v2.1.2
(Optional) Verify your source code consistency.
git status && git log -n1
On branch v2.1.2 nothing to commit, working tree clean
commit 7f4da1db9c7b12b17fbeaf874bde7f2aff6b1192 (HEAD -> v2.1.2, tag: v2.1.2)
Build the Sonic binary using the provided configuration.
make all
Check the Sonic binary version (the most recent version is v2.1.2).
build/sonicd version
(Optional, root) Transfer the new binaries to the bin folder for system-wide access.
sudo mv build/sonic* /usr/local/bin/
This step applies only if you did not run the client before or you want to launch with a new, clean copy of the Sonic database.
Note that the database of the Sonic client versions 2.0.1 to 2.0.7 is fully compatible with the new Sonic client version v2.1.2. If your node has been running one of the versions v2.0.1 to v2.0.7, and the node has been shut down gracefully, your database can be reused, and you can skip this step.
Download the most recent Sonic network genesis file. Based on your node designated feature set, you need to choose between “pruned” and “full” versions of the genesis file. The pruned one is used by validators so that the database footprint is minimal. The full version contains all the network history and is used for the archive node.
The genesis file will be used to prime your database and will allow you to join the network and synchronize with it after priming. Please double-check the downloaded genesis file using the provided checksum.
You can obtain the selected genesis file here:
Download the genesis file.
wget https://genesis.soniclabs.com/sonic-mainnet/genesis/sonic-38000-full.g
(Optional) Download the genesis checksum file.
wget https://genesis.soniclabs.com/sonic-mainnet/genesis/sonic-38000-full.g.md5
(Optional) Validate the genesis file consistency.
md5sum --check sonic-38000-full.g.md
Expected output is: sonic-38000-full.g: OK
Prime Sonic Database From Downloaded Genesis
Use the sonictool app (created during the building process as build/sonictool) to prime a validated archive state database for the Sonic client.
Start the genesis expansion for archive mode.
GOMEMLIMIT=50GiB sonictool --datadir --cache 12000 genesis --mode rpc
Start the genesis expansion for validator mode.
GOMEMLIMIT=50GiB sonictool --datadir --cache 12000 genesis --mode validator
The last step of the genesis processing is the state validation. Please check that the output log contains a message with the correct root hash:
StateDB imported successfully, stateRoot matches module=gossip-store index=42999003 root="6ee505...b8e7c0"
With the Sonic node binary created and the state database available, you are ready to start the node on the new version and synchronize its state with the network.
1. Stop Current Node
Stop the running instance gracefully. If you use Systemd manager to handle the Sonic node control, execute the stop procedure: systemctl stop sonicd
Other management systems may require different shutdown procedures. You may also use the general OS termination signal via pkill sonicd. But in this case, you need to make sure the client was terminated, and the control system did not attempt to restart it automatically.
Wait until the node terminates gracefully. Make sure the node is not running: ps aux|grep sonicd.
This step is extremely important for validators. If you run more than one client instance with the same validator key unlocked, your nodes may unintentionally violate the network rules, and your stake may be lost.
2. Start New Node
Use the node database path (<datadir>) from the previous installation or the new expansion created in the previous step.
Start the node using the new client version.
systemctl start sonicd
Use ≈90% of the RAM as the GOMEMLIMIT value. The limit should always be set. If not done correctly, your node may experience random crashes and subsequent state database corruption. Use ≈12 GiB of the RAM as the --cache value.
Replace the <datadir> with the correct path to the database. We recommend that validators use the --mode validator flag to obtain a smaller database footprint. Different starting flags may need to be added to start an archive node with Web3 RPC and WebSocket interfaces on the node.
GOMEMLIMIT=50GiB sonicd --datadir <datadir> --cache 12000 --nat extip:<public external IP address>
May 26, 2025
Synchronized access to cached block hashes to prevent rare incorrect RPC returns
Added NoArchiveError check before sending block notifications
Updated Tosca dependency
e44b0188 – Update Tosca dependency
00c1f2af – Synchronize cached block hash access (#209)
124dc66e – Add NoArchiveError check for notifications (#214)
a4e31329 – Update to v2.0.6-dev (#217)
v2.0.5
April 11, 2025
April 28, 2025
Verified archive block height before sending subscriber notifications
Switched eth_call simulation to GETH for large code handling in state override
Fixed test infrastructure and updated Go to v1.24
ea9e3631 – Add missing dependency
2d9284a8 – Use GETH for eth_call with large code (#189)
135b69cc – Fix BlockInArchiveTest infra & Go 1.24
e95926e4 – Update indirect dependencies (#121)
v2.0.4
March 15, 2025
March 26, 2025
Enabled transaction replay on empty blocks
Added block overrides for RPC calls
Updated NoBaseFee VM parameter for transaction replay
#26 – Replay transactions on empty blocks
#30 – Add block overrides for RPC
#104 – Update NoBaseFee VM config
v2.0.3
Feb 6, 2025
Feb 19, 2025
Updated go-ethereum dependency to add on-curve check for unmarshaled public keys
Improved intrinsic gas error detection
Added SetStorage on Carmen adapter
Allowed profiler/tracer stop calls even if never started
ecc88ecd – Fix version commit/date (#15)
2340cc37 – Accept profiler/tracer stop calls (#17)
325fb5ea – Implement SetStorage on Carmen adapter (#2)
8cc06953 – Update go-ethereum for on-curve check (#5)
v2.0.2
Jan 23, 2025
Jan 31, 2025
Enhanced RPC gas capping
Added getAccount RPC method
Improved finalized/safe block tag handling
Reduced event payload fetching during streaming
19dc2691 – Remove dev from meta version (#394)
3f86ba1c – RPC gas capping (#391)
b9545c63 – Implement getAccount RPC (#370)
1a233d03 – Update version to v2.0.2 (#387)
v2.0.1
-
Dec 2, 2024
-
-
v2.0.0
-
Nov 29, 2024
-
-
v2.0.7
June 26, 2025
TBA
• Improved error handling in debug_traceBlock — now uses error field and supports empty blob cases
252c9ee0 – Fix error handling in debug_traceBlock (#307)
v2.0.6
May 6, 2025
The second season of the airdrop and Kaito program are ending on November 1, 2025. Future incentive programs will be announced at a later stage.
The S airdrop will distribute 190,500,000 S tokens to incentivize users of Sonic. The airdrop will be distributed using Sonic Points, Sonic Gems, and Game Gems.
The S airdrop spans multiple seasons, with an undisclosed amount of the total airdrop allocated to each season. The first season ended on June 18, 2025, and the second season began immediately after.
Visit the to track your points.
For historical information about previous seasons of the airdrop, find the relevant pages here:
For season 1 of the airdrop, 25% of your allocation is immediately available, while the remaining 75% vests over 270 days as NFT positions that are tradable on the by Paintswap.
A linear decay mechanism applies to the vested portion, allowing you to claim early at the cost of a penalty that burns a portion of your tokens. This approach prevents sudden surges in circulating supply by burning tokens from users who choose to claim early. It also incentivizes recipients to stay active on-chain while waiting for an optimal time to claim the remainder of their allocation.
The chart below illustrates how many tokens will be burned based on when users choose to claim their vested airdrop allocation.
Andrew earns 1,000 S in the Sonic airdrop. Andrew can claim his 25% liquid allocation immediately and receive 250 S in his wallet. 90 days pass and Andrew returns to the claim portal, deciding he would like the rest of his airdrop. As 90 days have passed by, he can claim 249.75 S tokens (33.3 of the remaining 750 token allocation) but must burn 500.25 S (66.7% of his locked allocation).
Bob earns 10,000 S in the Sonic airdrop. Bob can claim his 25% liquid allocation immediately and receive 2,500 S. Bob is excited to use his S in the ecosystem and decides he would like all of his eligible airdrop allocation after day 30. Bob claims again (the final 75% portion), receiving 1,110 S and burning 6,667.5 S (88.9% of the final portion).
We are working with and to manage and oversee our points and airdrop designs through data-backed decision-making.
OpenBlock’s data-driven incentive modeling platform powers over $2B in annual incentive spend and has been a leading provider of rewards design and efficacy analysis for leading protocols in the space including EigenLayer, Lido, Linea, Mode, Arbitrum, Solana, Sui, and many others. To initiate and sustain its ecosystem, Sonic will utilize OpenBlock’s incentive modeling frameworks, ensuring continuous and balanced growth for all actors in the system.
Sentio is an industry-leading indexing service that aids in streamlining continuous point tracking, helping retrieve historical states of all user positions to update user points upon every interaction. With its high-performance database infrastructure, engineered to handle queries at unprecedented speeds, Sentio enables the onboarding of tens of thousands of new users easily and efficiently.
As part of the Sonic Foundation’s research and commitment to this airdrop, we have sought legal opinions to ensure its success.
The program will likely need to exclude any sanctioned country or person including all those who are citizens or residents of or residing in (the “Restricted Countries”): Belarus, Burundi, Central African Republic, Congo, Cuba, DPRK (North Korea), Guinea, Guinea-Bissau, Iran, Iraq, Lebanon, Libya, Mali, Myanmar (Burma), Republic of South Sudan, Russia, Somalia, Sudan, Syria, Ukraine, the Crimea, Donetsk, and Luhansk regions of Ukraine, Venezuela, Yemen, or Zimbabwe.
These potential provisions may include:
Geoblocking: Implementing geo-blocking measures for all restricted countries
Self-declaration: Requiring participants to say they are not from one of the restricted countries
Discretionary exclusion: The Sonic Foundation reserves the right to exclude any wallet address at its sole discretion
There will be a comprehensive set of terms and conditions provided at the program’s launch.
Explore the tooling and infrastructure platforms currently available on Sonic below. This list is regularly updated as new projects integrate the Sonic chain.
— Quick Overview — Introduction — Fail-Safe Mechanism — Fast Lane — Looking Into the Future — Frequently Asked Questions
The Sonic Gateway is our native bridge that facilitates token transfers between Ethereum and Sonic. The bridging process consists of three steps:
Deposit Deposit your assets into the bridge, which takes ~15 minutes on Ethereum to achieve finalization and only ~1 second on Sonic.
Heartbeat After your deposit is confirmed, your assets will be bridged at the next heartbeat, which are intervals that bridge user assets in batches to ensure gas efficiency. A heartbeat occurs every ~10 minutes from Ethereum to Sonic and ~1 hour the other way. You can pay a Fast Lane fee to trigger an immediate heartbeat.
Claim Claim your bridged assets on the destination chain. That’s it! You’re now free to explore the Sonic ecosystem with your new assets.
In today’s evolving blockchain landscape, a native, secure bridge is critical for ecosystem health, ensuring true interoperability and preventing network isolation. Yet, many current solutions on both layer 1S and layer 2S compromise security and speed —resulting in over to bridge hacks.
The Sonic Gateway is a revolutionary, secure bridge between Ethereum and Sonic that offers:
Security: The Gateway includes a fail-safe mechanism that safeguards user assets. If the Gateway experiences prolonged failure (14 consecutive days), users can recover their bridged funds on Ethereum.
Speed: Asset bridging is processed in intervals called "heartbeats" to ensure gas efficiency — every 10 minutes from Ethereum to Sonic and hourly in reverse.
Additionally, the Gateway makes Sonic an active participant on Ethereum as it spends ETH through its contracts.
The Sonic Gateway includes a fail-safe mechanism that allows users to retrieve bridged assets on the original chain if the Gateway experiences a failure. In the highly unlikely event that the Gateway or the Sonic chain is down for 14 consecutive days, users are able to reclaim their bridged assets on Ethereum.
The 14-day period is immutable and cannot be altered by Sonic Labs or any third party after deployment. Importantly, this period is not intended as a contest period but rather as an essential feature that ensures users retain custody of their bridged funds on the originating chain.
Assets bridged through the Sonic Gateway are processed in intervals called "heartbeats", ensuring gas efficiency by bundling bridging transactions together. For assets moving from Ethereum to Sonic, these heartbeats occur every 10 minutes, while Sonic to Ethereum heartbeats occur every hour.
During each interval, all queued transactions are processed simultaneously. While this system reduces costs, it may introduce waiting periods for users needing their assets bridged immediately. To address this, Fast Lane allows users to bypass the wait for a small fee and have their bridge transaction processed instantly.
Fast Lane works by adding an additional heartbeat to the Gateway. This means all other queued assets waiting to be bridged are also processed immediately, effectively accelerating the entire network. By using Fast Lane, users not only avoid delays and seize timely opportunities but also contribute to the broader ecosystem's efficiency, ensuring faster bridging for everyone involved.
By enabling canonical access to native assets from other layer-1 platforms, the Gateway fosters a secure and thriving economy on the Sonic network.
Users can directly access these canonical assets on Sonic while maintaining asset security. The Sonic Gateway thus provides safe access to high-demand assets that natively exist outside the Sonic network.
Transaction Stuck in Heartbeat The relay service that processes heartbeats may occasionally experience downtime. If your transaction appears stuck for more than an hour, please check our official channels for status updates. The service is monitored and will be brought back online promptly.
Claiming From a Multisig While possible, it requires careful proof generation. For the smoothest experience, we recommend using a standard EOA wallet with our Gateway UI.
Fee Monetization (FeeM) on Sonic lets builders earn 90% of the network fees their apps generate — creating a sustainable revenue stream without relying on fundraising. Inspired by Web2 models like YouTube, FeeM rewards developers for the traffic they drive.
FeeM also challenges the extractive "app chain" model by allowing builders to earn 90% of their app's network fees without the need to launch a separate chain. This approach removes the high costs, infrastructure overhead, and interoperability challenges typically associated with app chains.
By integrating monetization directly into the network layer, FeeM simplifies revenue capture and supports scalable, efficient app development within a unified, developer-friendly ecosystem.
In Fee Monetization, double counting is prevented by accurately tracking gas consumption within the virtual machine. The system traces all internal calls in a transaction and splits the reward based on the gas each sub-operation consumes.
This ensures that the sum of rewards across different projects never exceeds the total transaction fee. An example is given below.
A trade consumes 100,000 units of gas with a total FeeM reward of 0.017 S.
Inside this transaction, there are operations related to two projects: Project A and Project B.
Project A, the DEX aggregator, is responsible for consuming 37,000 units of gas, while Project B, the liquidity pool on the DEX with which the aggregator interacts, uses 63,000 units of gas.
The total reward is split based on the gas consumption:
The chart below illustrates how the FeeM oracle infrastructure traces each sub-operation and distributes the transaction fee spent on the calls based on gas consumed.
This page is specific to season 2 of the airdrop.
The second season of the airdrop and Kaito program are ending on November 1, 2025. Future incentive programs will be announced at a later stage.
Sonic Points are user-focused airdrop points that can be earned as part of the ~200 million S airdrop. Designed to boost liquidity on Sonic and strengthen its ecosystem, our points program positions Sonic as a premier hub for DeFi enthusiasts and users seeking to maximize the potential of their assets.
To earn Sonic Points, deploy whitelisted assets across various DeFi apps. These points will be distributed over multiple seasons as NFT positions, ensuring long-term sustainability and preventing sudden supply shifts.
— How To Earn Points — User Points — App Gems — Loyalty Multiplier — Whitelisted Assets — Airdrop Points Dashboard — Terms and Conditions
By deploying as liquidity on participating apps, users will earn points. A list of is available on the points dashboard.
To earn points for providing liquidity (LPs), both tokens in the pair must be whitelisted. If only one or neither token is whitelisted, no points will be earned. Points are calculated as the average of the two asset multipliers. For example, an S/USDC LP would earn 10x points (average of 12x and 8x).
The S airdrop includes a developer-focused portion, where apps compete for an airdrop allocation known as . Apps can redeem these Gems for S tokens, which they can then distribute to their users however they want.
To decide how these S tokens are distributed to their users, each app will run its own independent points program, entirely at its discretion. The app may consider various things, such as the amount of liquidity a user has deployed, the duration of deployment, and the specific pools to which a user has added liquidity.
As a user, you will be earning points regardless if you've deployed your assets on an app. Your goal is to identify which app has the points program that will offer the highest return for your liquidity. The challenge lies in maximizing your overall rewards by combining the yield earned from providing liquidity with the points earned from the app's points program.
To encourage consistency and prevent farming or drop-off cycles, a loyalty multiplier is in place.
Your season 1 performance sets your initial multiplier (from 1.0–2.0x), and your ongoing activity in season 2 can increase or decrease that value, up to a maximum of 3.0x and a minimum of 1.0x.
The multiplier applies to EOAs only (for now) and updates automatically based on your activity. It will be visible in MySonic once available (not immediately at launch). This loyalty program will carry forward into future seasons.
To qualify for the S airdrop, you must deploy the whitelisted assets listed in the table below as liquidity on participating apps. The multipliers are applied to the points you earn.
The multipliers for each asset above are decided by which category the fall under in the table below.
Sonic reserves the right to determine the appropriate category for any app.
Whitelisted assets and their multipliers are subject to change. S tokens staked through MySonic are not eligible for points. Users who wish to stake can instead use liquid staking tokens.
The is a comprehensive platform where users can:
Check earned points
Check the list of participating apps
Get whitelisted assets through a simple interface
Generate a referral code and share with friends to earn extra points
View the for the Sonic points program.
Archive nodes store the entire history of the Sonic chain, including all historical states, transactions, and blocks since the genesis block.
These nodes handle historical data requests, useful for chain explorers or apps that require historical chain information. However, they do not validate transactions or create new blocks, which is the role of validator nodes.
To run an archive node on the Sonic mainnet or testnet, follow the steps below.
The minimal configuration for a Sonic archive node is a Linux server with 4 vCPU, 32 GB of RAM, and local SSD storage. We recommend at least 8 vCPU and 64 GB of RAM, but 128GB of RAM is generally preferable for high-demand nodes.
You will need ≈1TB of free local SSD space to achieve good performance and speed. The configuration details depend on your specific use case.
The IOPS throughput and random access latency of the state DB persistent storage determine the performance of Sonic. For a smooth installation and fast response time, we recommend a local NVMe or a local SSD drive.
A remote block device, e.g. AWS Elastic Block Store (EBS), does not provide the required latency and IOPS performance.
Building the Sonic binary requires the essential software compilation tools and the language version 1.22 or newer to be available. Please refer to your Linux distribution manuals to obtain the development tools installed on your system.
Download the Sonic source code from the following GitHub repository.
Switch to the most recent .
Build the Sonic binary using the provided configuration.
Transfer the new binaries to the bin folder for system-wide access (optional).
Download the most recent network archive genesis file for the .
The genesis file will be used to prime your local state database and will allow you to join the network and synchronize with it. Please check the downloaded genesis file using the provided checksum.
The expected output is sonic.g: OK.
Use the sonictool app (created during the building process as build/sonictool) to prime a validated archive state database for the Sonic client. Start the genesis expansion.
The last step of the genesis processing is the state validation. Please double-check that the output log contains the following messages with details about the verified state:
With the Sonic app created and the database primed in the previous step, you are ready to start the node and synchronize its state with the network.
Use the node database path (<datadir>) from the previous step.
Use ≈90% of the RAM as the GOMEMLIMIT value.
Use ≈12 GiB of the RAM as the --cache value.
Additional starting flags may need to be added to start Web3 RPC and WebSocket interfaces on the node. Add the following flags to enable the Web3 HTTP interface. Adjust your listening IP address, port, CORS, and list of enabled APIs for your specific needs.
Add the following flags to enable the WebSockets interface. Adjust your listening IP address, port, origin, and list of enabled APIs for your specific needs.
Now, start your node with the sonicd application.
All apps on Sonic are eligible to participate in Fee Monetization. To apply, visit the and click Apply for FeeM.
The application process consists of registering your app to participate in FeeM, followed by registering your app's associated contracts to verify ownership.
Visit the , connect your admin wallet, and click Apply for FeeM. The registration form will request several details from you.
Below is a list of all important contract addresses relevant to the Sonic network.
Tokens:
0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38
npm install --save-dev @nomicfoundation/hardhat-toolboxrequire("@nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: "0.8.26",
networks: {
sonic: {
url: "https://rpc.soniclabs.com",
chainId: 146,
accounts: [SONIC_PRIVATE_KEY]
},
sonicTestnet: {
url: "https://rpc.testnet.soniclabs.com",
chainId: 57054,
accounts: [SONIC_PRIVATE_KEY]
}
},
etherscan: {
apiKey: {
sonic: "YOUR_SONICSCAN_API_KEY",
sonicTestnet: "YOUR_SONICSCAN_TESTNET_API_KEY"
},
customChains: [
{
network: "sonic",
chainId: 146,
urls: {
apiURL: "https://api.sonicscan.org/api",
browserURL: "https://sonicscan.org"
}
},
{
network: "sonicTestnet",
chainId: 57054,
urls: {
apiURL: "https://api-testnet.sonicscan.org/api",
browserURL: "https://testnet.sonicscan.org"
}
}
]
}
};API_KEY=your_sonicscan_api_key# For mainnet
npx hardhat verify --network sonic DEPLOYED_CONTRACT_ADDRESS [CONSTRUCTOR_ARGUMENTS]
# For testnet
npx hardhat verify --network sonicTestnet DEPLOYED_CONTRACT_ADDRESS [CONSTRUCTOR_ARGUMENTS]async function main() {
// Deploy contract
const Contract = await ethers.getContractFactory("YourContract");
const contract = await Contract.deploy(constructorArg1, constructorArg2);
await contract.waitForDeployment();
console.log("Contract deployed to:", await contract.getAddress());
// Wait for some block confirmations
await new Promise(resolve => setTimeout(resolve, 30000));
// Verify the contract
await hre.run("verify:verify", {
address: await contract.getAddress(),
constructorArguments: [constructorArg1, constructorArg2]
});
}npm install --save-dev hardhat-flattenernpx hardhat flatten contracts/YourContract.sol > flattened.sol4551d1fc – Prepare v2.0.5 release (#201)
e3f7b4c8 – Check archive height before notifications (#149)
48cdac00 – Update to v2.0.5-dev (#171)
f9eb911a – Fix intrinsic gas error recognition (#4)
46908a5c – Update module name to 0xsoniclabs/sonic (#1)
Minor bug fixes
79519713 – Fix error propagation (#389)
cda79533 – Handle finalized/safe block tags (#388)
0e1599a6 – Skip event payload fetch in streaming (#372)
7265d537 – Use data from proof (#371)
View a leaderboard that displays the points and Gems earned by users and apps
S, wS, stS, beS, anS, wanS, OS, wOS, vS, Origin ARM
12x
aSonUSDC, bUSDC.e-20, stkscUSD, wstkscUSD, vgUSDC, aprUSDC, sonicUSD, ghUSDC, SHADOW, x33, METRO, SWPX, BEETS, xSILO, BRUSH, EQUAL, FLY
10x
scUSD, USDC, USDT
8x
WETH, scETH, stkscETH, wstkscETH, WBTC, scBTC, stkscBTC, wstkscBTC
4x
Sonic Tokens
12x
Ecosystem Tokens
10x
Yield Bearing Stablecoins
10x
Pegged Stablecoins
8x
ETH/BTC
4x
Yield Bearing ETH/BTC
4x


Sonic automatically allocates 10% of this fee to the network validators.
Project A receives 37% of the reward (0.00629 S).
Project B receives 63% of the reward (0.01071 S).
The total reward still adds up to 100% of the 0.017 S FeeM reward, ensuring no over-distribution.


33.4%–22.3%
211–240
22.3%–11.2%
241–270
11.2%–0%
0–30
100%–88.9%
31–60
88.9%–77.8%
61–90
77.8%–66.7%
91–120
66.7%–55.6%
121–150
55.6%–44.4%
151–180
44.4%–33.4%

180–210
git clone https://github.com/0xsoniclabs/Sonic.gitgit fetch --tags && git checkout -b v2.1.2 tags/v2.1.2make allsudo cp build/sonic* /usr/local/bin/wget https://genesis.soniclabs.com/sonic-mainnet/genesis/sonic.gwget https://genesis.soniclabs.com/sonic-mainnet/genesis/sonic.g.md5
md5sum --check sonic.g.md5GOMEMLIMIT=50GiB sonictool --datadir <datadir> --cache 12000 genesis <genesis path>StateDB imported successfully, stateRoot matches module=gossip-store index=1 root="1ccba39...9ea2be"StateDB imported successfully, stateRoot matches module=gossip-store index=1 root="9601e5...c3d639"--http --http.addr=0.0.0.0 --http.port=18545
--http.corsdomain=* --http.vhosts=*
--http.api=eth,web3,net,ftm,txpool,abft,dag,trace,debug--ws --ws.addr=0.0.0.0 --ws.port=18546 --ws.origins=*
--ws.api=eth,web3,net,ftm,txpool,abft,dag,trace,debugGOMEMLIMIT=50GiB sonicd --datadir <datadir> --cache 12000 --nat extip:<public external IP address>Owner address Wallet that will manage your FeeM registration.
Rewards recipient address Address that will receive FeeM revenue when claimed.
Dispute contact Email to be used for communication if you dispute a contract.
Metadata Information about your app, such as logo, name, and website.
After completing this step, the UI will guide you through registering your app's associated contracts to verify ownership.
To verify ownership of the contracts you want to include in your FeeM application, you’ll need to add a small code snippet to them.
Choose the Auto-verify option
Copy and paste the code snippet into your contract
Deploy your contract and run the new registerMe function
Your contracts are now verified and included in FeeM, and you can proceed to the next step.
If your contract is not upgradable or you're unable to interact with them from an EOA or through other means, please choose the Manual verification option and follow the steps.
Once your app is approved to FeeM, you will start earning 90% of the network fees it generates.
To claim, visit the Fee Monetization dashboard, connect with your admin wallet, and claim your rewards. These will be sent to the recipient address you provided during the initial application step.
If you prefer to register your app and its contracts manually instead of using the UI described above, follow the instructions below. However, we recommend using the Fee Monetization dashboard to register.
Create a metadata config file in JSON format with the following parameters:
Host the file in a publicly accessible location. Ensure that anyone can download the JSON file via a browser and that the hosting site supports HTTPS. A 200×200px PNG logo, no larger than 32 KiB, is sufficient.
Go to the FeeM ProjectsRegistrar smart contract and execute the register function providing all the required information. A unique Project ID will be assigned to your registration in response. Use this ID to identify your project in subsequent calls.
Include the code snippet below directly in your contract and run the new function. Replace the <Your FeeM Project ID> placeholder with your actual FeeM Project ID.
Your app and its contracts are now integrated into FeeM. Proceed to Step 3 above to learn how to claim your rewards.
If your contract is not upgradable or you're unable to interact with them from an EOA or through other means, please contact Sam Harcourt on Telegram for manual contract verification.
The FeeM Core: 0x0b5f073135df3f5671710f08b08c0c9258aecc35
Projects Registrar: 0x897d37f040Ec8DEFFD0ae1De743e1b1a14cf221f
Projects' Contracts Registrar: 0xDC2B0D2Dd2b7759D97D50db4eabDC36973110830
Dispute Resolver: 0xF2169D8A17aA40cc31e1b43E4FbB2d19CA099310
0x50c42dEAcD8Fc9773493ED674b675bE577f2634b
0x29219dd400f2Bf60E5a23d13Be72B486D4038894
0xe715cba7b5ccb33790cebff1436809d36cb17e57
0x6047828dc181963ba44974801ff68e538da5eaf9
Core Contracts:
0xFC00FACE00000000000000000000000000000000
0xcA11bde05977b3631167028862bE2a173976CA11
0x3561607590e28e0848ba3B67074C676D6D1C9953
0x3561607590e28e0848ba3B67074C676D6D1C9953
Gateway Infrastructure (on Sonic):
0xD2f1e904dAf7446686F8057b7dfeb068c75D29A9
0x836664B0c0CB29B7877bCcF94159CC996528F2C3
0x12727D4169a42A9b5E3ECB11A6d2c95553d3f447
0xB5B371B75f9850dDD6CCB6C436DB54972a925308
0x134E4c207aD5A13549DE1eBF8D43c1f49b00ba94
: 0xE34e6851a4a3763e1d27aa7ac5980d2D33C2d315
0x9Ef7629F9B930168b76283AdD7120777b3c895b3
: 0x0B3fe0c10C050270a9bc34271987989B6CF2107C
0x1D3c99DA3CEF5C26f02a86dC7D685efa40176bb7
: 0x1071405A4736535C545580064039A235827ee6D4
Gateway Infrastructure (on Ethereum):
0x921B147a90Ef738BBb7c2c89D88ea9d8Af3e9306
0xB7e8CC3F5FeA12443136f0cc13D81F109B2dEd7f
0x72965045A6691E5A74299D1e878f303264D4D910
0xf2b1510c2709072C88C5b14db90Ec3b6297193e4
: 0x0c40Ae1c82401EA741953D3f026ADc07BE9e7943
0xa1E2481a9CD0Cb0447EeB1cbc26F1b3fff3bec20
: 0x4cbd824685F1E21B119F230B54d65C5a7D2a5330
0x7390251Bf35AA7eA7C196fc4750bd5d6c5918329
0xB0bECf0fBfE431D42bA0FbD8dFBFbB0DCFd62Da4
: 0x13bd43A6BE5795D4A4E3Efc4baC21Cd36Ae9e68A
Tokens:
0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38
0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51
Contracts:
0xcA11bde05977b3631167028862bE2a173976CA11
Tokens:
0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38
0xA4879Fed32Ecbef99399e5cbC247E533421C4eC6
Contracts:
0xcA11bde05977b3631167028862bE2a173976CA11
The Sonic Blaze testnet (2.0) will be depreciated soon.
This page is specific to season 2 of the airdrop.
The second season of the airdrop and Kaito program are ending on November 1, 2025. Future incentive programs will be announced at a later stage.
Sonic Gems are developer-focused airdrop points designed to reward apps for driving user engagement and innovation. These Gems can be redeemed for S tokens, which apps can then distribute as rewards to their users.
This system helps apps grow by driving consistent user activity and maintaining long-term engagement.
— What are Sonic Gems? — Distribution of Gems — Gems Revocation Policy
Sonic Gems are airdrop points exclusively designed for apps. Each season, a fixed supply of Gems is allocated to apps based on performance metrics. Apps can track their progress through the .
To distribute the S tokens earned through Gems to their users, apps must manage the process independently. For example, an app could:
Run their own internal points programs
Claim Gems and distribute S to users in season 3
Join on Telegram for further support
While there’s no strict requirement for apps to share a specific percentage of their claimed S tokens with their users, the design of Gems incentivizes generosity. Apps that share a larger portion of their claimed S with their communities are rewarded more favorably compared to those that do not.
Tokenizing Gems is strictly prohibited. Any app that does so will be instantly disqualified from the entire season.
Sonic Gems are distributed by considering factors such as category type, Sonic exclusivity, revenue generation, and effective reward distribution, promoting fairness and incentivizing active participation.
The competitive PvP nature and fixed supply of Gems mean that an app's Gem balance may fluctuate daily, influenced by the performance of other apps on the platform.
Below are the key criteria that will determine an app's share of Gems in season 1.
Apps are assessed across several weighted categories, with each app assigned a weight based on its primary category. For season 1, the specific weights are detailed below. If an app falls into multiple categories, the weight of its dominant category will be applied.
Apps will receive a pro-rata share of Sonic Gems based on their final weights, determined by the calculations below.
The following actions by the app can cause their Sonic Gems to be revoked.
Incentivizing Project Tokens or NFTs with Gems Allocating Gems as rewards for activities like holding, staking, or providing liquidity (LPing) for a project’s token or NFT. For apps that have a voting mechanism to direct emissions, Gems can be used as vote incentives for any pool other than those that contain the project's token.
Suspicious Distribution Practices Distributing large quantities of Gems non-transparently, such as allocating them disproportionately to insiders or KOLs without clear disclosure.
Misrepresenting Gem Redistribution Providing false information about the amount of claimed S being distributed to users during any season.
Users are encouraged to report any suspicious activity or malpractice to Sonic Labs.
Sonic nodes are generally stable and can run for extended periods without operator intervention. However, in rare cases, the software may encounter failures.
This page outlines the most common causes of such failures, suggests configuration adjustments to prevent them, and provides recovery steps to help you get your node back online as quickly as possible.
Regardless of the reason, the outcome of a failure is always the same. The node uses a database to track the state of all accounts, smart contracts, transactions, and the consensus data.
Parts of the database is kept in memory during normal operation. Pre-calculated and updated data is eventually pushed into the persistent storage. If the update cannot finish properly, the persistent copy of the database is in an inconsistent state and can be corrupted.
{
"name": "MySuperCoolProject",
"image_url": "https://mysupercoolproject.com/icons/icon.png",
"website": "https://mysupercoolproject.com/"
}/// @dev Register my contract on Sonic FeeM
function registerMe() external {
(bool _success,) = address(0xDC2B0D2Dd2b7759D97D50db4eabDC36973110830).call(
abi.encodeWithSignature("selfRegister(uint256)", <Your FeeM Project ID>)
);
require(_success, "FeeM registration failed");
}3
Options / Derivatives
2
Yield Aggregators
2
GambleFi
2
Bridges
2
Apps are assigned different weights depending on their level of exclusivity to Sonic:
Weight 2: Exclusively available on Sonic
Weight 1: Primarily on Sonic but accessible elsewhere
Weight 0.5: Available across multiple chains
Note: An app's Sonic-native weight cannot be upgraded during a season. However, if an app takes actions that reduce its Sonic nativeness, its weight will be reduced immediately and remain in effect for the following season as well.
This assesses how effectively an app distributes its claimed S to its users. An app's incentive weight is determined by the percentage of its claimed S that was distributed to its users during the previous season.
For example, if an app distributed 100% of its claimed S from season 1 to its users, it’ll receive a weight of 1 in season 2, while distributing only 80% would give it a weight of 0.8.
While there’s no requirement for apps to distribute a specific amount of their claimed S to users, it’s mandatory for all apps to publicly disclose the percentage they intend to share with their communities.
This transparency allows users to make informed decisions about allocating their capital. Any instances of false communication or misuse of claimed S will result in blacklisting for subsequent seasons.
Point score is determined by calculating the total amount of Sonic Points that an app has generated for its users. This score is then divided by the total points generated across all eligible apps.
Revenue score rewards apps that drive real, sustainable usage.
Only fees from whitelisted assets count toward the revenue score. Revenue-generating apps are beneficial to the network as they:
Contribute directly to network fees and long-term value for S holders
Signal stronger product-market fit and user demand
Encourage more efficient use of incentives across the ecosystem
If your app creates real volume and generates real fees, you’ll earn more Gems.
Tokenization Tokenizing Gems in any way.
Yield Tokenization
4
Isolated / Modular Lending
4
Spot / CLOB DEX
3
Pooled Lending / CDPs
3
Perps
sonicd daemon terminates shortly after you attempt to start it, and the output log will contain an error message similar to this: In general, there are three major reasons for Sonic node failure:
Misconfiguration of the Node Software
The node resource management configuration is intentionally left for the node operator to decide. This opens options for resource sharing and fine tuning your node to the specific use case you need. If not configured properly, it may also lead to unexpected crashes and failures.
There are lots of different scenarios of the node utilization. Some of them are very predictable and easily controllable, others may be more random. This mostly applies to the RPC interface and its operation. If your RPC load can vary greatly, especially if it involves high input/output disparity calls like utilizing the debug namespace, your node may run out of RAM memory and be forcefully terminated by the operating system.
Soft failures, for example storage space exhaustion, are usually detected by the node software correctly. In this case, the node tries to terminate gracefully. If an unpredictable issue arises, the node may terminate forcefully leading to the startup failure described above. This usually happens due to a storage device failure, different types of I/O errors, forcefully imposed operating system limits (file descriptors, open sockets, etc.), or forced system restart.
Check for the environment variable GOMEMLIMIT to be present and set correctly. If the sonicd node is the only user space software running on the system, it should be set between 85% and 90% of the available RAM. Make sure to properly account for any other software running on your system, including modules executed only occasionally or on a schedule. The value should include units for clarity and readability — better use GOMEMLIMIT=28GiB instead of a value in bytes without the unit.
Check the cache size to be explicitly specified and set between 12GiB and 20GiB. Values lower than 12GiB may cause potential issues with processing large blocks. There is no real benefit going over 20GiB of cache. The value itself is specified in MiB. For example, --cache 12000 represents 12 GiB.
Check your operating system limits, especially for open file descriptors and/or sockets. Consult your operating system documentation for your case.
If you use Systemd or a similar software lifecycle management tool, check the shutdown timeout of the service. The node shutdown procedure, if deployed on a recommended solid state drive (SSD), usually takes less than 15 seconds. If you use a remotely connected persistent storage, especially if an intermediate layer like cloud virtualization, or Kubernetes is involved, the shutdown may take significantly longer. We recommend setting the timeout to at least 1 minute.
The most common reason for resource exhaustion leading to a forced node termination and the database corruption is the RPC interface utilization. If the allocated memory crosses a system imposed threshold, the node is terminated unexpectedly and your state DB will be corrupted.
Verify what other software components are utilizing the system resources
Repeated crashes of your Sonic node may suggest there is another system component utilizing the system resources. An example may be a cloud scheduled system update, log clean-up process, a solid state drive sweep and optimization, or a planed backup task. If not accounted for, these components may trigger RAM exhaustion. In such cases, the biggest consumer would be the Sonic node, and the system may decide to terminate it to free the resources needed to finish the pending work. Update your Sonic node resource limits, especially the GOMEMLIMIT and --cache , to account for these components.
Check the usage pattern of your node
Some types of RPC API calls have very high ratios between input and output size. An example would be debug and trace namespaces and batch API calls. The whole output has to be kept in memory until the user request is resolved. Configure your system according to the expected usage pattern. We recommend at least 64 GiB of RAM for regular RPC nodes. High demand nodes should run on 128 GiB RAM or more.
Do not over-provision cache and/or allocation limits
Increasing cache amount above 20GiB has a diminishing return. You should set it between 12 and 20 GiB. The memory allocated for the cache cannot be used to process RPC calls, and to store the responses to be transmitted to end users. Make sure to set the GOMEMLIMIT value so that the system has enough RAM available for the regular operating system tasks. This is usually between 85% and 90% of the available system RAM. A typical server operating system needs only around 1–2GiB to run properly, but the usage can spike up to 4GiB or more. If your node utilizes a software RAID, you should allocate enough RAM for the module to be able to effectively manage the RAID storage read/write operations.
Moderate access to public RPC API
If your node has a public RPC API interface, we strongly recommend to use a middleware layer moderating access to the node RPC port. A great start would be a proxy server, for example , or , configured to limit the number of parallel requests executed on the node interface. The proxy can create a queue for incoming calls before they can be safely pushed to the node for processing. You can also set the proxy to limit number of incoming calls from a single source, or a group of sources, and reject excessive traffic.
Load-balance your traffic
The best approach to handle unpredictable RPC API traffic is to use multiple backend nodes to resolve and balance the traffic based on resource consumption. This usually requires more complex infrastructure setup. The benefit of such approach is that a regular maintenance does not make your interface inaccessible. Using several smaller systems instead of a single overpowered one may allow you to better control your resources cost, and will make your system way more issue resistant as a whole. The downside is much more complex configuration and maintenance which usually requires knowledge of high availability system setup and scalable architecture deployment.
A hardware failure usually cannot be predicted, but there are some steps you can take to lower the impact of some types of failures.
Configure graceful shutdown, especially on cloud deployments Cloud-based systems offer obvious benefits compared to bare metal solutions. They can be deployed easily, scaled dynamically, and migrated very quickly between different regions and/or system groups. If you opt for this type of configuration, make sure the shutdown process of the node uses a graceful ACPI shutdown, or its equivalent, and is set to wait for the procedure to finish. If not possible, configure the shutdown timer so that your Sonic node has enough time to sync its cache with the persistent storage. Please refer to the node deployment guidelines for the usual termination times. A non-cloud environment usually does not suffer from migrations, or unexpected resets, however they still may need to be shutdown for a hardware maintenance. Make sure to configure your system timeouts and the shutdown procedure to always allow your Sonic node to close properly.
Use redundant storage (RAID) to prevent single drive failure caused crash
Persistent storage failure is the most common type of hardware issue you may encounter. The node state data can be easily obtained from the Sonic network. There is no exclusive content on your drive beyond the <datadir>/keystore folder. Surely, your account keys and the validator consensus keys are already backed up securely. However, if your storage drive holding the state DB fails, the system will inevitably crash. To prevent the immediate impact of such failure, you should utilize RAID storage with the redundancy level configured to match your resiliency expectations.
Use high availability deployment setup for up-time sensitive RPC systems As discussed above, if your RPC node is part of a critical infrastructure, you should always opt for some level of node redundancy. It would not only allow you to recover after an unexpected system failure, but will also help you perform regular maintenance without experiencing the whole system downtime. A great starting point may be a proxy based load balancer, for example .
A validator node must always use a single instance deployment. If you attempt to run multiple validator nodes with the same signing key, your validator will be penalized for double-signing, removed from the network, and your stake will be slashed.
Monitor your system health and resources
This may be obvious, but your system will age, and it will fail eventually. Modern systems usually do have sensors which can warn you about possible failures and shortages in advance. Refer to your system documentation for the details about available monitoring solutions, and system level alerts, allowing you to take appropriate steps to resolve an imminent crash before it happens.
If your node runs in the validator mode, it does not have enough data to recover from the failure on its own. After you resolve the reason of the node crash, you need to download the latest state snapshot and rebuild the corrupted database from it. Please refer to the validator node deployment guide for the instructions how to obtain and unpack the latest snapshot. You should consider upgrading your node to the latest available version of the node software before you proceed.
If your node runs in the RPC mode and it did run at least 15 minutes after the initialization from the snapshot before it crashed, you may be able to recover the live state from the archive database. In this case, follow these steps:
Identify and fix the reason for the crash.
Make sure you have the latest available Sonic node version. If your local version is outdated, build the latest Sonic node software. Use the version command to check your node version:
Try to recover the state from your archive database.
The heal will attempt to recover the state. If the healing succeeds, you can start your node normally and the node will finish syncing from the network. Any failure means your archive state is not consistent and cannot be used to recover from the failure.
If your heal process failed, you need to remove <datadir>/carmen and <datadir>/chaindata folders, download the latest archive or pruned database snapshot, and rebuild your state from them. Refer to the for the details of the process.
Validator nodes are critical to the Sonic chain, responsible for validating transactions and creating new blocks in accordance with the . These nodes ensure the integrity and security of the network by verifying data, participating in block creation, and maintaining the chain’s state.
Unlike , validator nodes focus on real-time operations rather than storing extensive historical data or responding to general API requests.
To run a validator node on the Sonic mainnet or testnet, follow the steps below.
$ sonicd version
Sonic
Version: 2.0.5
Git Commit: ea9e363178ea9fb28a723beb803fb5dcf223cbbc
...GOMEMLIMIT=28GiB sonictool --datadir <path> --cache 12000 healfailed to initialize the node: failed to make consensus engine:
failed to open existing databases: dirty state: gossip-21614: DEDevelopment Environment
Node.js 16 + (includes npm)
MetaMask browser extension
Funding Your Wallet
Native gas token (S on the Sonic testnet) for transaction fees
USDC test tokens — use the CCTP V2 Sample App to bridge USDC from another testnet
Step 1: Create a new project
Step 2: Install dependencies
Step 3: Verify package.json
Step 4: Add the scripts section (if needed)
Step 5: Run the dev server
Create src/clients.ts:
Create src/constants.ts:
Create src/App.tsx:
Create src/main.tsx:
Open http://localhost:5173 in your browser and start transferring USDC on the Sonic Blaze testnet!
tee -a /etc/security/limits.conf > /dev/null <<EOT
@sonic soft nofile 950000
@sonic hard nofile 950000
EOT[Service]
Type=simple
User=sonic
Group=sonic
Environment="GOMEMLIMIT=28GiB"
ExecStart=/usr/bin/sonicd --datadir=/var/lib/sonic --cache=16000
LimitNOFILE=934073
TimeoutSec=300mkdir usdc-transfer-app
cd usdc-transfer-app
npm init -ynpm install react@latest react-dom@latest \
@types/react@latest @types/react-dom@latest \
@vitejs/plugin-react@latest typescript@latest \
vite@latest viem@latest{
"name": "usdc-transfer-app",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"@vitejs/plugin-react": "^4.4.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"typescript": "^5.8.3",
"viem": "^2.28.0",
"vite": "^6.3.2"
}
}"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}npm run devimport { http, createPublicClient, createWalletClient, custom } from 'viem';
import { sonicBlazeTestnet } from 'viem/chains';
declare global {
interface Window {
ethereum: any;
}
}
export const publicClient = createPublicClient({
chain: sonicBlazeTestnet,
transport: http(),
});
export const walletClient = createWalletClient({
chain: sonicBlazeTestnet,
transport: custom(window.ethereum),
});export const USDC_CONTRACT_ADDRESS =
'0x391071Fe567d609E4af9d32de726d4C33679C7e2';
export const USDC_ABI = [
{
constant: false,
inputs: [
{ name: '_to', type: 'address' },
{ name: '_value', type: 'uint256' },
],
name: 'transfer',
outputs: [{ name: '', type: 'bool' }],
type: 'function',
},
{
constant: true,
inputs: [{ name: '_owner', type: 'address' }],
name: 'balanceOf',
outputs: [{ name: 'balance', type: 'uint256' }],
type: 'function',
},
];import React, { useEffect, useState } from 'react';
import { publicClient, walletClient } from './clients';
import { USDC_CONTRACT_ADDRESS, USDC_ABI } from './constants';
import {
type Address,
type Hash,
type TransactionReceipt,
} from 'viem';
function USDCApp() {
const [account, setAccount] = useState<Address>();
const [balance, setBalance] = useState<string>();
const [hash, setHash] = useState<Hash>();
const [receipt, setReceipt] = useState<TransactionReceipt>();
const [recipient, setRecipient] = useState('');
const [amount, setAmount] = useState('');
const [isTransferring, setIsTransferring] = useState(false);
// Fetch USDC balance
const fetchBalance = async (address: Address) => {
const raw = await publicClient.readContract({
address: USDC_CONTRACT_ADDRESS,
abi: USDC_ABI,
functionName: 'balanceOf',
args: [address],
}) as bigint;
setBalance((Number(raw) / 1e6).toFixed(2));
};
// Connect wallet
const connect = async () => {
const [addr] = await walletClient.requestAddresses();
setAccount(addr);
fetchBalance(addr);
};
// Transfer USDC
const transferUSDC = async (e: React.FormEvent) => {
e.preventDefault();
if (!account || !recipient || !amount) return;
try {
setIsTransferring(true);
const value = BigInt(Math.floor(Number(amount) * 1e6));
const { request } = await publicClient.simulateContract({
account,
address: USDC_CONTRACT_ADDRESS,
abi: USDC_ABI,
functionName: 'transfer',
args: [recipient as Address, value],
});
const txHash = await walletClient.writeContract(request);
setHash(txHash);
const rcpt = await publicClient.waitForTransactionReceipt({ hash: txHash });
setReceipt(rcpt);
await fetchBalance(account); // refresh balance
setRecipient('');
setAmount('');
} catch (err) {
console.error('Transfer failed:', err);
} finally {
setIsTransferring(false);
}
};
return (
<div>
<h1>USDC Transfer Sample App</h1>
{account ? (
<>
<p><strong>Connected wallet:</strong> {account}</p>
<p><strong>USDC balance:</strong> {balance ?? 'Fetching…'} USDC</p>
<form onSubmit={transferUSDC} style={{ marginTop: 20 }}>
<div style={{ marginBottom: 10 }}>
<label>
Recipient address
<input
type="text"
value={recipient}
onChange={e => setRecipient(e.target.value)}
placeholder="0x..."
style={{ marginLeft: 10, width: 300 }}
/>
</label>
</div>
<div style={{ marginBottom: 10 }}>
<label>
Amount (USDC)
<input
type="number"
value={amount}
onChange={e => setAmount(e.target.value)}
placeholder="0.00"
step="0.01"
min="0"
style={{ marginLeft: 10 }}
/>
</label>
</div>
<button type="submit" disabled={isTransferring}>
{isTransferring ? 'Transferring…' : 'Transfer USDC'}
</button>
</form>
{hash && (
<p style={{ marginTop: 20 }}>
<strong>Transaction hash:</strong> {hash}
</p>
)}
{receipt && (
<p style={{ marginTop: 10 }}>
<strong>Transaction status:</strong>{' '}
{receipt.status === 'success' ? 'Success' : 'Failed'}
</p>
)}
</>
) : (
<button onClick={connect}>Connect Wallet</button>
)}
</div>
);
}
export default USDCApp;import React from 'react';
import ReactDOM from 'react-dom/client';
import USDCApp from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<USDCApp />
</React.StrictMode>,
);<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>USDC Transfer Sample App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>npm run devState Updates
Ethereum → Sonic: Monitor StateOracle.lastBlockNum until it's >= deposit block
Sonic → Ethereum: Monitor StateOracle.lastBlockNum until it's >= withdrawal block
Proofs
Required for all claim operations
Generated using eth_getProof RPC call with correct storage slots
Must be RLP encoded in format: RLP.encode([RLP.encode(accountProof), RLP.encode(storageProof)])
Storage slots are calculated using:
Deposits: keccak256(abi.encode(depositId, uint8(7)))
Withdrawals: keccak256(abi.encode(withdrawalId, uint8(1)))
Gas Fees
Keep enough ETH/S for gas on both networks
Claim operations typically cost more gas due to proof verification
Security
Never share private keys
Always verify contract addresses
Test with small amounts first
Monitoring
Monitor transaction status on both networks
Keep transaction hashes for reference
Verify successful claims before proceeding
Minimum self-stake amount: 500,000 S
Maximum validator size: 15x self-stake
Rewards: ~6% APR initially, plus 15% of delegators' rewards and network fees
Mainnet RPC:
Testnet RPC:
WebSocket Endpoint: wss://rpc.soniclabs.com
Mainnet Explorer:
You can run your validator node on dedicated hardware (bare metal) or use a cloud provider. We recommend choosing one of the established providers, such as Google GCP or Amazon AWS.
At least 4 vCPUs and 32 GB of RAM
At least 1 Gbps redundant backbone connectivity for stable and uninterrupted network traffic
At least 1 TB of local SSD/NVMe storage. Remote block devices (e.g., AWS EBS) typically do not provide the required latency and random access performance. Google GCP N2D instances with local SSD or AWS i3en.xlarge with instance storage are good options.
Ubuntu LTS Server (64-bit) or a similar Linux distribution is recommended.
1 TB of local SSD/NVMe is sufficient for a validator database.
A Sonic node requires both TCP and UDP network traffic allowed on port 5050 by default. You can use --port <port> to customize this if needed.
You need the essential build tools and the latest Go compiler, version 1.24 or newer, to build the Sonic client and its bundled tools. Example (Ubuntu/Debian):
Install Go language compiler (Ubuntu/Debian):
Check the latest Sonic release and adjust commands if necessary:
You can confirm the Sonic release by running:
Optionally, copy the binaries to a system-wide location:
To participate in the Sonic network, you need a valid state database. The fastest way is to use a genesis file from the official repository. Download the appropriate genesis file. For the mainnet, for example:
Use sonictool to prime the state database. Adjust GOMEMLIMIT and --cache according to your available RAM size. For the most common cases, use 12GiB as --cache and ~90% of RAM as GOMEMLIMIT.
After processing, you should see a confirmation of a successfully imported state.
Now that your database is primed, start the node to synchronize it with the network. Ensure your firewall is configured correctly.
The Sonic node will connect to the network and advance its state by processing new blocks. Once fully synchronized, the "age" of new blocks should be only a few seconds.
Your Sonic node is now synchronizing. Next, create a wallet to identify and control your validator account. This wallet must hold the minimum amount you are going to use as the self-stake (500,000 S).
We recommend creating the wallet securely (e.g. a hardware wallet). If you choose to create it locally using sonictool:
Important: Keep your wallet and keys secure. Never share them.
A Sonic validator node signs consensus messages. Your node needs a validator signing key to participate. Create it on the server:
Follow the prompts and set a secure password. Note the public key (starts with 0xc00). This key will be used during registration.
Important: Back up your signing key. Although it cannot move funds, misuse could lead to penalties.
The network must recognize your validator key. Register by invoking the SFC (Staking and Consensus) contract:
SFC Contract Address: 0xFC00FACE00000000000000000000000000000000
Call createValidator with your validator public key and at least the minimum required stake (500,000 S). Sign this transaction with your validator wallet. After confirmation, query your validator ID using the getValidatorID function. The easiest way would be to open the Sonic explorer and navigate to the SFC address.
The contract is validated and you can interact with it using SonicScan and a connected Web3 wallet. The control validator account can be imported into your Web3 wallet either using the generated JSON key store or as your hardware wallet. With the account open, you can sign the createValidator transaction call specifying the amount of stake and the public key obtained in the previous step.
Stop the currently running node:
Wait for it to gracefully shut down. Never force-terminate it, as it could corrupt the database. Restart your node in validator mode, providing the validator ID, public key, and password file:
Your validator node will now participate in consensus and produce blocks.
Create a config file in JSON format that contains the following parameters (you can also leave parameters empty):
Host it somewhere so it is publicly accessible, such as in this example. Make sure anybody can download the JSON file using a browser and that the hosting site supports HTTPS. A 100x100 logo size is sufficient.
Now you need to insert the JSON URL into the STI contract.
Go to SonicScan and open the STI contract.
Hit Contract -> Write Contract.
Find the function updateInfo and paste the JSON URL.
Connect using your validator account Web3 wallet (the one you used to register).
Sign and execute the update.
Congratulations! You are now running a Sonic validator node.
// Ethereum (L1)
const ETH_CONTRACTS = {
TOKEN_DEPOSIT: "0xa1E2481a9CD0Cb0447EeB1cbc26F1b3fff3bec20",
TOKEN_PAIRS: "0xf2b1510c2709072C88C5b14db90Ec3b6297193e4",
STATE_ORACLE: "0xB7e8CC3F5FeA12443136f0cc13D81F109B2dEd7f"
};
// Sonic (L2)
const SONIC_CONTRACTS = {
BRIDGE: "0x9Ef7629F9B930168b76283AdD7120777b3c895b3",
TOKEN_PAIRS: "0x134E4c207aD5A13549DE1eBF8D43c1f49b00ba94",
STATE_ORACLE: "0x836664B0c0CB29B7877bCcF94159CC996528F2C3"
};// Network RPC endpoints
const ETHEREUM_RPC = "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY";
const SONIC_RPC = "https://rpc.soniclabs.com";
// Initialize providers
const ethProvider = new ethers.providers.JsonRpcProvider(ETHEREUM_RPC);
const sonicProvider = new ethers.providers.JsonRpcProvider(SONIC_RPC);
// Initialize signer with your private key
const PRIVATE_KEY = "your-private-key";
const ethSigner = new ethers.Wallet(PRIVATE_KEY, ethProvider);
const sonicSigner = new ethers.Wallet(PRIVATE_KEY, sonicProvider);async function bridgeToSonic(tokenAddress, amount) {
// 1. Check if token is supported
const tokenPairs = new ethers.Contract(ETH_CONTRACTS.TOKEN_PAIRS, TOKEN_PAIRS_ABI, ethProvider);
const mintedToken = await tokenPairs.originalToMinted(tokenAddress);
if (mintedToken === ethers.constants.AddressZero) {
throw new Error("Token not supported");
}
// 2. Approve token spending
const token = new ethers.Contract(tokenAddress, ERC20_ABI, ethSigner);
const approveTx = await token.approve(ETH_CONTRACTS.TOKEN_DEPOSIT, amount);
await approveTx.wait();
// 3. Deposit tokens
const deposit = new ethers.Contract(ETH_CONTRACTS.TOKEN_DEPOSIT, TOKEN_DEPOSIT_ABI, ethSigner);
const tx = await deposit.deposit(Date.now(), tokenAddress, amount);
const receipt = await tx.wait();
return {
transactionHash: receipt.transactionHash,
mintedToken,
blockNumber: receipt.blockNumber,
depositId: receipt.events.find(e => e.event === 'Deposit').args.id
};
}async function waitForStateUpdate(depositBlockNumber) {
const stateOracle = new ethers.Contract(SONIC_CONTRACTS.STATE_ORACLE, STATE_ORACLE_ABI, sonicProvider);
while (true) {
const currentBlockNum = await stateOracle.lastBlockNum();
if (currentBlockNum >= depositBlockNumber) {
return currentBlockNum;
}
await new Promise(resolve => setTimeout(resolve, 30000)); // Check every 30 seconds
}
}
async function generateProof(depositId, blockNum) {
// Generate storage slot for deposit
const storageSlot = ethers.utils.keccak256(
ethers.utils.defaultAbiCoder.encode(['uint256', 'uint8'], [depositId, 7])
);
// Get proof from Ethereum node
const proof = await ethProvider.send("eth_getProof", [
ETH_CONTRACTS.TOKEN_DEPOSIT,
[storageSlot],
ethers.utils.hexValue(blockNum) // important to use current stateOracle.lastBlockNum
]);
// Encode proof in required format
return ethers.utils.RLP.encode([
ethers.utils.RLP.encode(proof.accountProof),
ethers.utils.RLP.encode(proof.storageProof[0].proof)
]);
}
async function claimOnSonic(depositBlockNumber, depositId, tokenAddress, amount) {
// 1. Wait for state oracle update
console.log("Waiting for state oracle update to block ", depositBlockNumber);
const blockNum = await waitForStateUpdate(depositBlockNumber);
// 2. Generate proof
console.log("Generating proof...");
const proof = await generateProof(depositId, blockNum);
// 3. Claim tokens with proof
console.log("Claiming tokens...");
const bridge = new ethers.Contract(SONIC_CONTRACTS.BRIDGE, BRIDGE_ABI, sonicSigner);
const tx = await bridge.claim(depositId, tokenAddress, amount, proof);
const receipt = await tx.wait();
return receipt.transactionHash;
}async function bridgeToEthereum(tokenAddress, amount) {
// 1. Check if token is supported
const tokenPairs = new ethers.Contract(SONIC_CONTRACTS.TOKEN_PAIRS, TOKEN_PAIRS_ABI, sonicProvider);
const originalToken = await tokenPairs.mintedToOriginal(tokenAddress);
if (originalToken === ethers.constants.AddressZero) {
throw new Error("Token not supported");
}
// 2. Approve token spending
const token = new ethers.Contract(tokenAddress, ERC20_ABI, sonicSigner);
const approveTx = await token.approve(SONIC_CONTRACTS.BRIDGE, amount);
console.log("waiting... ", approveTx.hash);
await approveTx.wait();
// 3. Initiate withdrawal
const bridge = new ethers.Contract(SONIC_CONTRACTS.BRIDGE, BRIDGE_ABI, sonicSigner);
const tx = await bridge.withdraw(Date.now(), originalToken, amount);
const receipt = await tx.wait();
return {
transactionHash: receipt.transactionHash,
originalToken,
blockNumber: receipt.blockNumber,
withdrawalId: receipt.events.find(e => e.event === 'Withdrawal').args.id
};
}async function waitForEthStateUpdate(withdrawalBlockNumber) {
const stateOracle = new ethers.Contract(ETH_CONTRACTS.STATE_ORACLE, STATE_ORACLE_ABI, ethProvider);
while (true) {
const currentBlockNum = await stateOracle.lastBlockNum();
if (currentBlockNum >= withdrawalBlockNumber) {
return currentBlockNum;
}
await new Promise(resolve => setTimeout(resolve, 30000)); // Check every 30 seconds
}
}
async function generateWithdrawalProof(withdrawalId, blockNum) {
// Generate storage slot for withdrawal
const storageSlot = ethers.utils.keccak256(
ethers.utils.defaultAbiCoder.encode(['uint256', 'uint8'], [withdrawalId, 1])
);
// Get proof from Sonic node
const proof = await sonicProvider.send("eth_getProof", [
SONIC_CONTRACTS.BRIDGE,
[storageSlot],
ethers.utils.hexValue(blockNum) // important to use current stateOracle.lastBlockNum
]);
// Encode proof in required format
return ethers.utils.RLP.encode([
ethers.utils.RLP.encode(proof.accountProof),
ethers.utils.RLP.encode(proof.storageProof[0].proof)
]);
}
async function claimOnEthereum(withdrawalBlockNumber, withdrawalId, tokenAddress, amount) {
// 1. Wait for state oracle update
console.log("Waiting for state oracle update to block ", withdrawalBlockNumber);
const blockNum = await waitForEthStateUpdate(withdrawalBlockNumber);
// 2. Generate proof
console.log("Generating proof...");
const proof = await generateWithdrawalProof(withdrawalId, blockNum);
// 3. Claim tokens with proof
console.log("Claim tokens with proof...");
const deposit = new ethers.Contract(ETH_CONTRACTS.TOKEN_DEPOSIT, TOKEN_DEPOSIT_ABI, ethSigner);
const tx = await deposit.claim(withdrawalId, tokenAddress, amount, proof);
const receipt = await tx.wait();
return receipt.transactionHash;
}async function bridgeUSDC() {
try {
// USDC details
const USDC_ADDRESS = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const amount = ethers.utils.parseUnits("100", 6); // USDC has 6 decimals
// 1. Bridge USDC to Sonic
console.log("Initiating bridge to Sonic...");
const deposit = await bridgeToSonic(USDC_ADDRESS, amount);
console.log(`Deposit successful: ${deposit.transactionHash}`);
// 2. Claim USDC on Sonic
console.log("Waiting for state update and claiming on Sonic...");
const claimTx = await claimOnSonic(deposit.blockNumber, deposit.depositId, USDC_ADDRESS, amount);
console.log(`Claim successful: ${claimTx}`);
// Later: Bridge back to Ethereum
console.log("Initiating bridge back to Ethereum...");
const withdrawal = await bridgeToEthereum(deposit.mintedToken, amount);
console.log(`Withdrawal initiated: ${withdrawal.transactionHash}`);
// Claim on Ethereum
console.log("Waiting for state update and claiming on Ethereum...");
const finalClaim = await claimOnEthereum(
withdrawal.blockNumber,
withdrawal.withdrawalId,
withdrawal.originalToken,
amount
);
console.log(`Final claim successful: ${finalClaim}`);
} catch (error) {
console.error("Bridge operation failed:", error.message);
throw error;
}
}const STATE_ORACLE_ABI = [
"function lastBlockNum() external view returns (uint256)",
"function lastState() external view returns (bytes32)"
];
const ERC20_ABI = [
"function approve(address spender, uint256 amount) external returns (bool)",
"function allowance(address owner, address spender) external view returns (uint256)"
];
const TOKEN_PAIRS_ABI = [
"function originalToMinted(address) external view returns (address)",
"function mintedToOriginal(address) external view returns (address)"
];
const TOKEN_DEPOSIT_ABI = [
"function deposit(uint96 uid, address token, uint256 amount) external",
"function claim(uint256 id, address token, uint256 amount, bytes calldata proof) external",
"event Deposit(uint256 indexed id, address indexed owner, address token, uint256 amount)"
];
const BRIDGE_ABI = [
"function withdraw(uint96 uid, address token, uint256 amount) external",
"function claim(uint256 id, address token, uint256 amount, bytes calldata proof) external",
"event Withdrawal(uint256 indexed id, address indexed owner, address token, uint256 amount)"
];sudo apt-get update
sudo apt-get install -y build-essential gitsudo rm -rf /usr/local/go
wget https://go.dev/dl/go1.25.2.linux-amd64.tar.gz
sudo tar -xzf go1.25.2.linux-amd64.tar.gz -C /usr/local/
rm -f go1.25.2.linux-amd64.tar.gz
sudo tee /etc/profile.d/golang.sh > /dev/null <<EOT
export GOROOT=/usr/local/go
export GOPATH=\$HOME/go
export PATH=\$PATH:\$GOROOT/bin:\$GOPATH/bin
EOT
source /etc/profile.d/golang.shgit clone https://github.com/0xsoniclabs/Sonic.git
cd Sonic
git fetch --tags && git checkout -b v2.1.2 tags/v2.1.2
make allbuild/sonicd versionsudo mv build/sonic* /usr/local/bin/wget https://genesis.soniclabs.com/sonic-mainnet/genesis/sonic.gGOMEMLIMIT=54GiB sonictool --datadir ~/.sonic \
--cache 12000 genesis \
--mode validator sonic.gGOMEMLIMIT=54GiB sonicd --datadir ~/.sonic --cache 12000 --mode validatorsonictool --datadir ~/.sonic account newsonictool --datadir ~/.sonic validator newpkill sonicdGOMEMLIMIT=50GiB sonicd \
--datadir ~/.sonic \
--cache 12000 \
--mode validator \
--validator.id <your_validator_ID> \
--validator.pubkey <your_public_key> \
--validator.password <path_to_password_file>{
"name": "VALIDATOR_NAME", /* Name of the validator */
"logoUrl": "LOGO_URL", /* Validator logo (PNG|JPEG|SVG 100x100) starting https:// */
"website": "WEBSITE_URL", /* Website icon on the right */
"contact": "CONTACT_URL" /* Contact icon on the right */
}
/* It could look something like this 👇 */
{
"name": "SonicLabs",
"logoUrl": "https://repository.sonic.soniclabs.com/validator/sonic.svg",
"website": "https://www.soniclabs.com",
"contact": "https://www.soniclabs.com/contact"
}Monitor StateOracle updates for claim timing
Testnet Explorer: https://testnet.sonicscan.org
SFC Contract Address: 0xFC00FACE00000000000000000000000000000000
STI Contract (Validators' Information): 0xFf4cD89f549432c312c497628748d4d76AC180f6
Genesis Files: https://genesis.soniclabs.com
Validator/Name Logo
You can set a validator name and logo on the explorer. Check official repositories for instructions.
The STI contract on Sonic: 0xFf4cD89f549432c312c497628748d4d76AC180f6
Community and Help
Join Sonic community channels, follow updates, and use your stake to participate in network governance. If you have issues, the community can provide guidance.
Monitoring and Health
If your node goes offline, you stop earning rewards. Extended downtime (e.g. more than 5 days) may result in suspension, requiring you to withdraw and start over. Regular monitoring, maintenance, and backups are essential.



This repository demonstrates account abstraction on Sonic using both EIP-7702 and ERC-4337 standards through a fully functional on-chain tic-tac-toe game.
It showcases how Sonic is upgrading its infrastructure to support Ethereum's account abstraction features, enabling gasless transactions, smart account capabilities, and enhanced user experiences.
Sonic Testnet Deploy your own contracts using Hardhat Ignition (chain ID 14601)
Frontend Demo Requires a running for UserOperation submission
Bot Demo Interacts directly with deployed contracts
Fully decentralized 5x5 tic-tac-toe game with 4-in-a-row win condition
Prize token rewards (10 tokens for winners, one token for draws)
Time-limited moves (24-hour timeout protection)
Upgradeable smart contract using UUPS proxy pattern
Transform regular EOAs into smart accounts without changing addresses
Enable transaction batching and gas sponsorship for existing wallets
Demonstrate SET_CODE_TX_TYPE transaction format
Complete implementation of UserOperation flow
EntryPoint interaction for validation and execution
Support for both MetaMask integration and programmatic signing
Gas estimation and fee management
TargetCheckingPaymaster: Sponsors gas for whitelisted contract interactions
SignatureCheckingPaymaster: Validates authorized transactions with signature verification
Gas-free gameplay for users
Automated tic-tac-toe player using min-max algorithm
Monitors blockchain events and responds to game moves
Configurable joining delay and strategy selection
Complete event subscription and game state management
Vue.js web interface for game interaction
Two authentication methods:
MetaMask integration (requires pre-configured delegation)
Private key input (sets up delegation automatically)
EIP-7702 introduces a new transaction type that allows EOAs to delegate their execution logic to smart contracts:
No Address Change EOAs maintain their original addresses
Code Delegation EOA delegates code execution to a specified smart contract
Native Batching Execute multiple operations in a single transaction
Backward Compatible Works with existing infrastructure
Key Innovation: The SET_CODE_TX_TYPE transaction format with authorization lists enables EOAs to act as smart accounts without permanent migration.
ERC-4337 provides a complete account abstraction solution without protocol changes:
UserOperations Pseudo-transactions that encapsulate user intent
Bundlers Aggregate and submit UserOps to the blockchain
EntryPoint Singleton contract for validation and execution
Paymasters Services that sponsor gas fees
Key components:
Sender ERC-4337 compatible smart contract wallet
UserOperation Contains nonce, calldata, gas limits, and signatures
Bundler Collects UserOps and submits them on-chain
Paymaster Covers transaction fees on behalf of users
EIP-7702 and ERC-4337 are complementary, not competing standards:
EIP-7702 upgrades an EOA to execute smart contract code
The upgraded EOA implements ERC-4337's IAccount interface
The account can now receive UserOperations through EntryPoint
Paymasters can sponsor gas for the upgraded account
TicTacToe.sol: Main game contract with UUPS upgradeability
PrizeToken.sol: ERC20 token for game rewards
Simple7702Account.sol: EIP-7702 compatible account implementation (in /contracts/testing)
TargetCheckingPaymaster.sol: Paymaster that sponsors specific contract calls
senduserop
Demonstrates UserOperation creation and submission
EIP-7702 authorization signing
Gas estimation and fee calculation
Direct EntryPoint interaction
tictactoebot
Automated game player with an AI strategy
Event monitoring and subscription
Minimax algorithm implementation
Keystore management
Vue.js single-page application
UserOperation construction in the browser
MetaMask and private key support
Real-time game interaction
Comprehensive contract testing
Paymaster validation tests
Game logic verification
Gas usage optimization
Node.js 18+ and npm
Go 1.24+ (yes, 1.24 is correct - see go.mod)
Git
A funded wallet for deploying contracts and running the bundler
Create a .env file in the root directory:
Notes:
Private key should be without the '0x' prefix
Sonic RPC URL is already configured in hardhat.config.ts
Deploy to Sonic testnet (chain ID 14601):
The bundler aggregates UserOperations and submits them to the EntryPoint:
The bundler RPC will be exposed at: http://localhost:3000/rpc
Notes:
Use --unsafe flag for RPCs that don't support debug_traceCall (most public RPCs)
The mnemonic account needs sufficient balance to send transactions (0.1 S recommended)
The bot automatically plays games and demonstrates event monitoring:
Bot flags:
--gameAddress: TicTacToe contract address
--startBlock: Block number to start event scanning (default: 1)
--joiningDelay: Time to wait before joining new games (default: 1 minute)
Open in your browser.
Run the comprehensive test suite:
The TargetCheckingPaymaster validates:
Account code hash matches whitelist
The target contract is approved
Gas fees are within limits
Board Size: 5x5 grid
Win Condition: 4 stones in a row
Rewards: 10 tokens for the winner, one token each for the draw
Timeout: 24 hours per move
Account abstraction benefits:
🔒 Enhanced security with smart account features
⛽ Gas sponsorship for better UX
📦 Transaction batching for efficiency
🔑 Flexible authentication methods
Implementation patterns:
Delegation Pattern EOA delegates to smart contract logic
Validation Pattern Custom signature validation in accounts
Sponsorship Pattern Paymasters cover gas costs
Batching Pattern Multiple operations in a single transaction
Smart account interface:
Paymaster interface:
Common issues and solutions:
"AA25 invalid account nonce": Account nonce mismatch - check EntryPoint.getNonce()
"AA33 reverted": Paymaster validation failed - check gas limits
"AA51 prefund too low": Insufficient paymaster deposit
"Not from self or EntryPoint": Invalid caller for account execution
Additional setup issues:
Frontend bundler connection: Update bundler URL in Vue components if not using default
Go version error: Ensure Go 1.24+ is installed (check with go version)
Contract deployment fails: Ensure wallet has sufficient funds and correct network is selected
Bot can't join games: Check keystore file permissions and passphrase
Real-time UserOperation construction and submission
Persistent Until Changed Delegation remains active until explicitly updated
Users benefit from both simple EOA interactions AND smart account features
SignatureCheckingPaymaster.sol: Paymaster with signature validation
Note: EntryPoint contract is imported from @account-abstraction/contracts
--blocksPerQuery: Max block range for event queries (default: 10000)--keystore: Path to keystore JSON file
--keystorePass: Path to keystore passphrase file (optional)
Bundler errors: Ensure the mnemonic account has funds for gas

git clone <repository-url>
cd TicTacToeDemo# Install Node.js dependencies
npm install
# Install Go dependencies
go mod download
# Install frontend dependencies
cd frontenddemo
npm install
cd ..# Required for deployment
PRIVATE_KEY=your_private_key_here_without_0x_prefixnpx hardhat compile# Deploy complete TicTacToe system
npx hardhat ignition deploy ./ignition/modules/TicTacToe.ts --network sonic-testnet
# Deploy paymasters separately (if needed)
npx hardhat ignition deploy ./ignition/modules/TargetCheckingPaymaster.ts --network sonic-testnet
npx hardhat ignition deploy ./ignition/modules/SignatureCheckingPaymaster.ts --network sonic-testnet# For Sonic testnet
npx hardhat ignition verify --network sonic-testnet# Clone the bundler (if not already done)
git clone https://github.com/eth-infinitism/bundler
cd bundler
# Configure and run
yarn install
yarn run bundler --network https://rpc.soniclabs.com/ \
--mnemonic path/to/mnemonic.txt \
--entryPoint 0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108 \
--unsafe
# Build the bot
cd cmd/tictactoebot
go build
# Run with configuration
./tictactoebot \
--rpcUrl https://rpc.soniclabs.com/ \
--gameAddress 0xYourGameAddress \
--keystore path/to/keystore.json \
--joiningDelay 30scd frontenddemo
npm run dev
# Run all tests
npx hardhat test
# Run with gas reporting
REPORT_GAS=true npx hardhat test
# Run with detailed traces
npx hardhat test --fulltrace
# Run specific test file
npx hardhat test test/TicTacToe.tsstruct PackedUserOperation {
address sender; // Smart account address
uint256 nonce; // Anti-replay parameter
bytes initCode; // Account creation code (if needed)
bytes callData; // Execution calldata
bytes32 accountGasLimits; // Verification and call gas limits
uint256 preVerificationGas; // Gas for bundler overhead
bytes32 gasFees; // maxPriorityFee and maxFeePerGas
bytes paymasterAndData; // Paymaster address and data
bytes signature; // Account signature
}auth := types.SetCodeAuthorization{
ChainID: chainId,
Address: accountImplementation, // Smart account code
Nonce: accountNonce,
}
signedAuth := SignSetCode(privateKey, auth)interface IAccount {
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData);
}interface IPaymaster {
function validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external returns (bytes memory context, uint256 validationData);
}