Somnia 백서

Somnia

원문

bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 54쪽 중 21쪽

ct\` function with the code below: ```javascript // Write to the "changeName" function const txHash = await walletClient.writeContract({ address: CONTRACT_ADDRESS, abi: ABI, functionName: "changeName", args: ["Emmanuel!"], }); console.log("Transaction sent. Hash:", txHash); console.log("Waiting for transaction confirmation..."); // Wait for the transaction to be confirmed const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); console.log("Transaction confirmed. Receipt:", receipt); // Read the updated "greet" function const updatedGreeting = await publicClient.readContract({ address: CONTRACT_ADDRESS, abi: ABI, functionName: "greet", }); console.log("Updated greeting:", updatedGreeting); ``` Save the file and run the node command to see your responses logged into the console. ```bash node index.js ``` Congratulations, you have successfully performed a WRITE operation on your Smart Contract deployed on Somnia. 🎉 <br> # Verifying via Explorer This document explains how to verify smart contracts on Somnia Mainnet using Blockscout. It replaces the old explorer-based verification flow. ## How It Works Somnia Mainnet Explorer is Blockscout-based and uses Blockscout verification endpoints. There are 4 primary verification methods: 1. Verification via Explorer UI 2. Verification via Blockscout Smart Contract Verification API 3. Verification via Hardhat plugin 4. Verification via Foundry (forge) {% hint style="info" %} Recommendation: For production contracts, use Standard JSON Input whenever possible. It includes full compiler metadata and gives the most reliable results. {% endhint %} ## 1. Explorer UI {% stepper %} {% step %} #### Go to the explorer Go to <https://explorer.somnia.network/> . {% endstep %} {% step %} #### Open the verification page Open `Other -> Verify Contract`.\ \ ![](https://2122549367-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkYErT9t3BJtpPfejLO6I%2Fuploads%2FSlchfrWTTR6EZXC71kbf%2Fimage.png?alt=media\&token=229f0b3e-24e4-4152-b3ae-4677b8181dd3) {% endstep %} {% step %} #### Enter contract details Enter your contract address and select a verification method. {% endstep %} {% step %} #### Match compilation parameters Match all compilation parameters exactly with your deployment settings: * Compiler version * EVM version * Optimizer and runs * Constructor args * License type {% endstep %} {% step %} #### Verify and publish Click `Verify and Publish` to complete the process. {% endstep %} {% endstepper %} ### Main UI verification options * Solidity (Flattened source code) * Solidity (Standard JSON input) * Solidity (Multi-part files) * Solidity (Sourcify) * Vyper (Single contract file) * Vyper (Multi-part files) * Vyper (Standard JSON input) ## 2. API Verification (Blockscout v2) ### Base URL `https://mainnet.somnia.w3us.site/api/v2` ### Service health check To check whether the verification service is active: ```bash curl -L "https://mainnet.somnia.w3us.site/api/v2/smart-contracts/verification/config" ``` If healthy, it returns `200`. ### 2.1 Flattened Solidity verification ```bash curl -L \ --request POST \ --url "https://mainnet.somnia.w3us.site/api/v2/smart-contracts/<CONTRACT_ADDRESS>/verification/via/flattened-code" \ --header "Content-Type: application/json" \ --data '{ "compiler_version": "v0.8.24+commit.e11b9ed9", "license_type": "mit", "source_code": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\ncontract A { }", "is_optimization_enabled": true, "optimization_runs": 200, "contract_name": "A", "evm_version": "paris", "autodetect_constructor_args": true }' ``` ### 2.2 Standard JSON Input verification ```bash curl -L \ --request POST \ --url "https://mainnet.somnia.w3us.site/api/v2/smart-contracts/<CONTRACT_ADDRESS>/verification/via/standard-input" \ --header "Content-Type: multipart/form-data" \ --form "compiler_version=v0.8.24+commit.e11b9ed9" \ --form "contract_name=MyContract" \ --form "files[0]=@./standard-input.json" \ --form "autodetect_constructor_args=true" \ --form "license_type=mit" ``` ### 2.3 Multi-part Solidity verification ```bash curl -L \ --request POST \ --url "https://mainnet.somnia.w3us.site/api/v2/smart-contracts/<CONTRACT_ADDRESS>/verification/via/multi-part" \ --header "Content-Type: multipart/form-data" \ --form "compiler_version=v0.8.24+commit.e11b9ed9" \ --form "license_type=mit" \ --form "is_optimization_enabled=true" \ --form "optimization_runs=200" \ --form "evm_version=paris" \ --form "files[0]=@./contracts/MyContract.sol" \ --form "files[1]=@./contracts/Lib.sol" ``` ### License values (example) In Blockscout API, `license_type` is sent as a string: * `none` * `unlicense` * `mit` * `gnu_gpl_v2` * `gnu_gpl_v3` * `gnu_lgpl_v2_1` * `gnu_lgpl_v3` * `bsd_2_clause` * `bsd_3_clause` * `mpl_2_0` * `osl_3_0` * `apache_2_0` * `gnu_agpl_v3` * `bsl_1_1` ## 3. Hardhat Verification For Somnia Blockscout, use the `@nomicfoundation/hardhat-verify` plugin. ### Installation ```bash npm install --save-dev @nomicfoundation/hardhat-verify ``` ### Example `hardhat.config.ts` ```ts import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-verify"; const config: HardhatUserConfig = { solidity: "0.8.24", networks: { "somnia-mainnet": { url: "<SOMNIA_RPC_URL>", accounts: ["<PRIVATE_KEY>"] } }, etherscan: { apiKey: { // A real API key is not required for Blockscout verification "somnia-mainnet": "abc" }, customChains: [ { network: "somnia-mainnet", chainId: 5031, urls: { apiURL: "https://mainnet.somnia.w3us.site/api", browserURL: "https://mainnet.somnia.w3us.site/" } } ] }, sourcify: { enabled: false } }; export default config; ``` ### Verification command ```bash npx hardhat verify \ --network somnia-mainnet \ <DEPLOYED_CONTRACT_ADDRESS> \ "<CONSTRUCTOR_ARG_1>" "<CONSTRUCTOR_ARG_2>" ``` ## 4. Foundry Verification Use Blockscout verifier in Foundry as follows: ```bash forge verify-contract \ --rpc-url <SOMNIA_RPC_URL> \ <DEPLOYED_CONTRACT_ADDRESS> \ src/MyContract.sol:MyContract \ --verifier blockscout \ --verifier-url https://mainnet.somnia.w3us.site/api/ ``` To verify at deployment time: ```bash forge create \ --rpc-url <SOMNIA_RPC_URL> \ --private-key $PRIVATE_KEY \ src/MyContract.sol:MyContract \ --verify \ --verifier blockscout \ --verifier-url https://mainnet.somnia.w3us.site/api/ ``` ## Troubleshooting * Compiler version must match exactly (`0.8.24` vs `0.8.24+commit...` matters). * Optimizer settings must exactly match deployment settings. * Verification fails if constructor arguments are incorrect or missing. * For multi-file projects, prefer Standard JSON Input or Multi-part over Flattened. * If errors persist, retry first via UI and then via API, and compare payload differences. ## Useful Links * Blockscout Verification API docs: <https://docs.blockscout.com/devs/verification/blockscout-smart-contract-verification-api> * Blockscout UI docs: <https://docs.blockscout.com/devs/verification/blockscout-ui> * Hardhat verify plugin (Blockscout): <https://docs.blockscout.com/devs/verification/hardhat-verification-plugin> * Foundry verification (Blockscout): <https://docs.blockscout.com/devs/verification/foundry-verification> # Debug Playbook ## 1. Revert Decoding Debugging smart contracts on the **Somnia Network** requires an understanding of how and why transactions fail. Every reverted transaction carries encoded data that can reveal the root cause of failure, whether it’s due to logic errors, insufficient gas, failed access checks, or internal Solidity panics. ### 1.1 Anatomy of a Revert When a transaction fails on Somnia, the EVM halts execution and returns **revert data**, an ABI-encoded payload that follows one of these three formats: <table><thead><tr><th>Type</th><th>Selector</th><th width="217.08984375">Description</th><th>Example</th></tr></thead><tbody><tr><td><code>Error(string)</code></td><td><code>0x08c379a0</code></td><td>Standard revert reason with message</td><td><code>require(balance > 0, "Zero balance");</code></td></tr><tr><td><code>Panic(uint256)</code></td><td><code>0x4e487b71</code></td><td>Internal error (e.g., overflow, div/0, invalid enum)</td><td><code>assert(x > 0);</code></td></tr><tr><td>Custom Errors</td><td>Function selector of custom error</td><td><code>error Unauthorized(address caller);</code></td><td></td></tr></tbody></table> On Somnia, these behave identically to Ethereum but may differ in **gas costs** and **stack trace length** depending on the validator node configuration. ### 1.2 Catching and Displaying Reverts in Hardhat When running tests or scripts on Somnia, wrap calls in `try/catch` to capture the revert reason. {% code title="example.ts" %} ```ts try { await treasury.withdraw(1000); } catch (error: any) { console.log('Revert reason:', error.reason || error.message); console.log('Full error data:', error.data || error.error?.data); } ``` {% endcode %} In **Chai matchers**: {% code title="chai-example.ts" %} ```ts await expect(treasury.connect(user).withdraw(1000)) .to.be.revertedWith('Insufficient funds'); ``` {% endcode %} If your contract uses **custom errors**, Hardhat will not automatically print the name. Decode it manually: {% code title="decode-custom-error.ts" %} ```ts const iface = new ethers.utils.Interface(contractABI); try { await treasury.connect(attacker).withdraw(9999); } catch (error: any) { const data = error.data || error.error?.data; if (data) { const decoded = iface.parseError(data); console.log(`Custom Error: ${decoded.name}`); console.log('Arguments:', decoded.args); } } ``` {% endcode %} ### 1.3 Decoding Panic Codes Internal Solidity panics correspond to low-level EVM exceptions. Somnia propagates these codes like any other EVM chain. | Panic Code | Description | Typical Cause | | ---------- | --------------------------------- | -------------------------- | | `0x01` | Assertion failed | Logic invariant broken | | `0x11` | Arithmetic overflow/underflow | Unchecked math operation | | `0x12` | Division by zero | Incorrect math division | | `0x21` | Invalid enum conversion | Out-of-bounds value | | `0x31` | Storage array index out of bounds | Bad loop or mapping access | | `0x32` | Memory array index out of bounds | Corrupt array operation | To detect Panic errors dynamically: {% code title="detect-panic.ts" %} ```ts if (error.data?.startsWith('0x4e487b71')) { const code = parseInt(error.data.slice(10), 16); console.log('Panic Code:', `0x${code.toString(16)}`); } ``` {% endcode %} ### 1.4 Advanced Revert Inspection with Hardhat Traces Hardhat’s tracing layer can reveal the full execution path of a revert. {% code title="trace" %} ```bash npx hardhat test --trace ``` {% endcode %} You’ll see nested calls, gas usage per function, and exactly where the failure occurred. This is invaluable for multi-contract interactions like on-chain governance or liquidity management. Example output: ``` CALL treasury.withdraw └─ CALL token.transfer -> reverted with reason: 'Insufficient balance' ``` ### 1.5 Custom Error Decoding for Verified Contracts If a Somnia contract is verified on the explorer, you can fetch its ABI dynamically to decode errors programmatically: {% code title="fetch-abi.ts" %} ```ts import axios from 'axios'; const abiURL = `https://explorer.somnia.network/api?module=contract&action=getabi&address=${address}`; const { data } = await axios.get(abiURL); const iface = new ethers.utils.Interface(JSON.parse(data.result)); ``` {% endcode %} Then use `iface.parseError(error.data)` to decode reverts directly from on-chain logs or transactions. *** ## 2. Common Error Patterns on Somnia Even experienced developers encounter recurring issues. Below are the **most common EVM-level errors** observed when deploying or testing on Somnia Testnet (Shannon) and Mainnet. | Error Type | Cause | Fix | | ------------------------- | ---------------------------------- | ----------------------------------------------- | | `execution reverted` | Fallback revert with no message | Add explicit revert messages or decode ABI data | | `out of gas` | Gas exhausted mid-call | Use `estimateGas()` or increase gas limit | | `invalid opcode` | Calling a non-existent function | Validate ABI and deployed bytecode | | `nonce too low` | Pending transaction not mined yet | Wait for confirmation or reset nonce | | `replacement underpriced` | Gas bump too small | Raise gas price by 10–20% | | `static call violation` | State-changing call via `eth_call` | Use `.sendTransaction()` instead | ### 2.1 Example: Catching a Custom Error in Somnia Treasury Contract {% code title="Treasury.sol" %} ```solidity error Unauthorized(address caller); function mint(address to, uint amount) external { if (msg.sender != owner) revert Unauthorized(msg.sender); _mint(to, amount); } ``` {% endcode %} Decoding in JS: {% code title="catch-unauthorized.ts" %} ```ts try { await treasury.connect(randomUser).mint(addr, 100); } catch (e: any) { const iface = new ethers.utils.Interface(['error Unauthorized(address caller)']); const decoded = iface.parseError(e.data); console.log('Unauthorized address:', decoded.args[0]); } ``` {% endcode %} ### 2.2 Handling Complex Contract Interactions When interacting with multi-layered DeFi protocols or bridging modules on Somnia, reverts can originate **several calls deep**. Use Hardhat’s trace or Foundry’s `-vvvv` verbosity to see the full stack. Foundry example: {% code title="foundry-verbosity" %} ```bash forge test -vvvv ``` {% endcode %} This reveals each opcode execution, event emission, and revert reason. ### 2.3 Invalid ABI or Proxy Conflicts Many Somnia projects use **upgradeable proxies**. Reverts from a proxy may originate in the implementation contract. If you get a generic `execution reverted`, verify you’re using the correct implementation ABI: {% code title="get-impl.ts" %} ```ts const implAddr = await provider.getStorageAt(proxyAddress, '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'); const iface = new ethers.utils.Interface(implementationABI); ``` {% endcode %} *** ## 3. Transaction Simulation Simulating transactions allows developers to predict revert causes, estimate gas usage, and test behaviors **without risking real SOMI or STT**. ### 3.1 Fork Somnia Networks Locally Create a local fork of Somnia Mainnet or Shannon Testnet: {% code title="hardhat-fork" %} ```bash npx hardhat node --fork https://api.infra.mainnet.somnia.network ``` {% endcode %} Or in configuration: {% code title="hardhat-config.ts" %} ```ts networks: { hardhat: { forking: { url: process.env.SOMNIA_RPC_TESTNET, blockNumber: 123456, //example } } } ``` {% endcode %} This mirrors on-chain state locally, so you can safely replay any transaction. ### 3.2 Using callStatic for Dry-Run Simulation `callStatic` runs a transaction without broadcasting or altering state. {% code title="callstatic.ts" %} ```ts try { const result = await treasury.callStatic.withdraw(1000); console.log('Call successful:', result); } catch (error: any) { console.log('Simulation failed with reason:', error.reason); } ``` {% endcode %} ### 3.3 Using eth\_call Manually For raw RPC simulation: {% code title="eth-call.ts" %} ```ts const tx = { to: contract.address, data: contract.interface.encodeFunctionData('stake', [amount]) }; const result = await provider.call(tx); console.log('Returned data:', result); ``` {% endcode %} If the call reverts, inspect `error.data` to decode it with the ABI. See the [JSON-RPC API Reference](/developer/json-rpc-api) for `eth_call` parameter details and error codes. ### 3.4 Impersonating Accounts for Privileged Actions Simulate admin or contract-controlled operations: {% code title="impersonate.ts" %} ```ts await network.provider.request({ method: 'hardhat_impersonateAccount', params: ['0xAdminAddress'] }); const admin = await ethers.getSigner('0xAdminAddress'); await treasury.connect(admin).setFee(5); ``` {% endcode %} Stop impersonation when finished: {% code title="stop-impersonate.ts" %} ```ts await network.provider.request({ method: 'hardhat_stopImpersonatingAccount', params: ['0xAdminAddress'] }); ``` {% endcode %} ### 3.5 Snapshot and Rollback Control Snapshots let you test different outcomes quickly: {% code title="snapshot.ts" %} ```ts const snapshot = await network.provider.send('evm_snapshot', []); await treasury.mint(100); await network.provider.send('evm_revert', [snapshot]); ``` {% endcode %} This resets the blockchain to its previous state instantly. ### 3.6 Simulating On-Chain Transactions If you have a failed transaction hash from Somnia Mainnet: {% code title="replay-tx.ts" %} ```ts const tx = await provider.getTransaction('0x123...'); await provider.call({ to: tx.to!, data: tx.data }); ``` {% endcode %} This reproduces the failure locally and lets you inspect the revert reason directly in Hardhat. ### 3.7 Advanced Fork Testing with Foundry {% code title="anvil-forge" %} ```bash anvil --fork-url https://dream-rpc.somnia.network --fork-block-number 3456789 forge test -vvvv ``` {% endcode %} You can use cheatcodes like: {% code title="foundry-cheatcodes.sol" %} ```solidity vm.startPrank(admin); contract.withdraw(1000); vm.stopPrank(); ``` {% endcode %} ### 3.8 Gas Profiling and Cost Analysis Somnia gas costs can differ from Ethereum due to consensus differences. Always estimate gas usage per function: {% code title="estimate-gas.ts" %} ```ts const gas = await contract.estimateGas.executeTrade(orderId); console.log('Estimated gas:', gas.toString()); ``` {% endcode %} Compare against Shannon and Mainnet to identify anomalies. ### 3.9 Full Transaction Lifecycle Test {% stepper %} {% step %} **Fork Somnia Testnet** Create a fork of the testnet to reproduce on-chain state locally. {% endstep %} {% step %} **Impersonate the deployer account** Use impersonation to perform privileged actions and reproduce behavior. {% endstep %} {% step %} **Run callStatic to simulate critical functions** Dry-run core functions to inspect return values and revert reasons. {% endstep %} {% step %} **Capture reverts and decode with ABI** Decode revert data, custom errors, and panic codes to get actionable context. {% endstep %} {% step %} **Use snapshot/revert to iterate quickly** Take snapshots to test multiple scenarios and revert between them. {% endstep %} {% step %} **Once clean, deploy and verify on testnet** After local verification, deploy to the testnet and verify behavior. {% endstep %} {% step %} **Run same steps on mainnet fork before release** Final validation on a mainnet fork ensures production parity. {% endstep %} {% endstepper %} *** {% hint style="info" %} Summary * Always **decode revert data** rather than relying on generic error strings. * Decode **custom errors** to get structured failure context. * Use **forked local environments** for safe and realistic debugging. * Combine **callStatic**, **trace**, and **snapshot/revert** for fast iteration. * Validate gas behavior across testnet and mainnet for accurate production cost. Debugging on Somnia means understanding the EVM intimately. Every revert, panic, and trace is a clue—decode them, simulate safely, and ship with confidence. {% endhint %} # Deploying Smart Contracts # Building DApps # Tokens and NFTs Tokens and NFTs form the backbone of value and ownership on Somnia. This section walks you through how to **create, deploy, and interact** with ERC-20, ERC-721, and ERC-1155 contracts on the Somnia Network. You’ll learn how to: * Deploy fungible tokens (ERC-20) and configure supply and minting logic * Create and manage NFTs (ERC-721 / ERC-1155) for digital assets and collectibles * Integrate token interactions into your dApps and subgraphs * Understand token st
프로젝트로 돌아가기