# Security Audit — TOIN Ecosystem (BotoIn)

**Report version:** 2.0
**Date:** 2026-08-29
**Scope:** TOIN smart contracts on **Ethereum (Sepolia + Mainnet)**, **TON (testnet)** and **Solana (devnet)**
**Review type:** Static code audit (manual review) + on-chain verification

---

## 1. Executive summary

The TOIN ecosystem smart contracts deployed across the three networks
(test/testnet) and the project's auxiliary contracts (co-owner burner wallets) were audited.

**Overall result: the EVM contract base is solid and follows standard patterns
(OpenZeppelin, ReentrancyGuard, SafeERC20, Pausable).** No critical vulnerabilities exploitable
with real funds were found, partly because **all deployments are on test
networks** (Sepolia, TON testnet, Solana devnet) with no real value at risk.

The most relevant findings are concentrated in:

| # | Severity | Network | Finding |
|---|---|---|---|
| H-01 | **High** | TON | The jetton `ToinToken.tact` **is not a functional standard Jetton (TEP-74)**; the mint is disabled and the transfer is not interoperable. |
| H-02 | **High** | EVM + TON | `CoOwnedWallet` grants **unlimited delegation** to the bot (parentB) during the expiry window. |
| M-01 | **Medium** | EVM | `StakingRewards.recoverTokens` allows the owner to withdraw **staked** tokens (owner "rug pull" risk). |
| M-02 | **Medium** | Solana | The program **does not enforce the supply cap** (100M); the mint authority can mint without limit. |
| M-03 | **Medium** | Solana | Explicit Anchor authorization constraints are missing (everything is delegated to the SPL Token). |
| M-04 | **Medium** | EVM | `MultiSigWallet`: owner management by `owners[0]` (single point) and failed txs marked as executed. |
| M-05 | **Low/Medium** | EVM | Fee withdrawals by a single owner (not multisig) in `FeeCollector`/`SubscriptionRegistry`. |
| L-01..L-05 | **Low** | EVM | Various: no month cap in `subscribe`, `payReferral` without referrer validation, etc. |
| I-01..I-05 | **Info** | All | Dead code, deprecated trait, supply centralization, etc. |

**Priority recommendation:** before going to mainnet, rewrite the TON Jetton to a
**standard TEP-74** implementation and harden bot delegation (per-operation limits,
allowlist, short expiry and secure custody of the bot's key).

---

## 2. Review scope

### 2.1 Ethereum / EVM (Solidity ^0.8.24, OpenZeppelin 5.x) — deployed on Sepolia

| Contract | Address (Sepolia) |
|---|---|
| `ToinToken` (ERC-20 + Burnable + Permit + Ownable) | `0xb352bA546E4bF7E311d8B82EcCCD84158ADc9259` |
| `ToinVesting` | `0xFb457A5aCA61644f2F6e19A85947FEFc1960dDf7` |
| `SubscriptionRegistry` | `0xF08a8b09f76b5fb69A332A140220eCF834A2FdB9` |
| `FeeCollector` | `0x4e75f2dA610041D80b7cEC4361066161FbD091E0` |
| `StakingRewards` | `0x48428de1E64882ff63f18c0dF7999A346796cf10` |
| `ReferralRegistry` | `0xBBC8AbD4b24C3fC5eeDded514e6264B4600cFCC1` |
| `MultiSigWallet` | `0x8D7d26797A7739Df186076d935DEeB5419521710` |
| `CoOwnedWallet` / `CoOwnedWalletFactory` | (burner wallets, in the codebase) |
| `CoOwnedWallet` / `CoOwnedWalletFactory` (v2, en Sepolia) | `Factory 0x637A9CBd13CC65FC110dFc40E64247E5B4aAe7b1` · burner de prueba `0x23D0B7B8aDF46f9c02C9395257cE0adf4c662219` ("BotoIn Burner Wallet #1788025848") |
| `ToinToken` (TOIN correcto en Sepolia, para pools V4) | `0xd5a6117E88D51eB2956eC76cffbA129bB7E3a53a` |
| **`CoOwnedWalletFactory` (v2, MAINNET — desplegado y verificado)** | **`0xB24A38fcF8eE292106d9f174d55D34372DfD9b41`** · verificado Etherscan (solc v0.8.24) · FeeCollector `0xFFaaa7422b02438e6CA54a9b30A50b2A85eC3c64` |

#### Pools de prueba TOIN en Uniswap V4 (Sepolia) — creados y operados por el bot
| Pool | fee / tickSpacing | Estado |
|---|---|---|
| TOIN/WETH | 3000 / 60 | creado y probado (bot vendió/compró) |
| TOIN/USDC | 3000 / 60 | creado y probado (bot compró) |
| TOIN/LINK | 3000 / 60 | creado y probado (bot compró) |
| TOIN/ETH | 3000 / 60 | creado y probado (bot vendió/compró) |

### 2.2 TON (Tact 1.6.13) — deployed on testnet

| Contract | Address (testnet) |
|---|---|
| `ToinToken.tact` (Jetton) | `kQBjNGQ9ugZRSX12DioCEhUs9OGaSbI5ON7q2xVlHT__kXZ7` |
| `CoOwnedWallet.tact` (mirror) | — (not deployed) |

### 2.3 Solana (Anchor 0.29 / Rust) — deployed on devnet

| Component | Address |
|---|---|
| Program `toin_token` | `ECL6k5H2MXXL8hcPLsFFKFAKtKk5r7u6gKKZ19xGxaRt` |
| TOIN mint (SPL, 9 decimals) | `tC5t97bu9Agxm4o41tmKyEyzCuffSCV96PBL9vP6Hi3` |

---

## 2.4 Description and use of the contracts

Each contract embeds its **description** and **usage** metadata in its **source** (EVM NatSpec,
Rust `//!`, Tact `///`). Summary of the ecosystem:

### Token (multi-chain)

| Network | Standard | Description | Usage |
|---|---|---|---|
| Ethereum (`ToinToken`) | ERC-20 | ERC-20 with **Burnable** + **Permit** (gasless approvals) and IPFS metadata via `setMetadataURI`. | Standard `transfer`/`approve`/`transferFrom`/`burn`/`permit`; the owner updates metadata. |
| TON (`ToinToken.tact`) | Jetton TEP-74 | Standard TEP-74 Jetton (minter + wallet), interoperable with Tonkeeper. | Transfer/receive via TEP-74; the owner updates the content (IPFS) with `SetContent`. |
| Solana (`lib.rs`) | SPL (Anchor) | SPL program with **on-chain supply cap** (`SupplyCaps` PDA) and real mint authority. | `initialize_mint` creates mint+SupplyCaps; `mint_tokens` mints validating authority and cap; `transfer_tokens`/`burn_tokens`. |

### Ecosystem contracts (Ethereum/Sepolia)

| Contract | Description | Usage |
|---|---|---|
| `ToinVesting` | Multi-beneficiary vesting (cliff + linear release). | Owner: `addSchedule`; `release` releases; `revoke` (revocable only) returns the unvested amount. |
| `SubscriptionRegistry` | On-chain PRO subscriptions (TOIN/USDC/ETH) with expiry. | Owner sets prices (`setPrice`/`setNativePrice`); `subscribe` extends PRO (max 120 months); `isActive` validates. |
| `FeeCollector` | Treasury for bot and ecosystem fees (ETH/ERC-20). | `deposit`/`depositToken` contribute; `withdrawETH`/`withdrawToken` withdraw (owner only). |
| `StakingRewards` | TOIN staking with TOIN rewards (Synthetix pattern). | `stake`/`withdraw`/`getReward`; owner injects the pool with `notifyRewardAmount`. |
| `ReferralRegistry` | On-chain referral program (unique codes, immutable referrer). | `registerCode`; referred with `setReferrer`; owner pays with `payReferral` (registered referrers only). |
| `MultiSigWallet` | N-of-M multisig for treasury and control (withdrawals, ownership, operator). | `submitTransaction`/`executeTransaction`; owner changes with supermajority + timelock. |
| `CoOwnedWallet` / `Factory` | Co-owner burner wallet (2 parents) with single authorization to the bot and per-operation limit. | `delegate` authorizes the bot; `exec`/`execBatch` operate; `maxValuePerOp` limits. |

> This metadata is also centralized in `config/toin-multichain-manifest.json` (fields
> `description`/`usage` per network and per contract) and in the exchange manifests generated in
> `config/exchanges/`.

---

## 3. Methodology

1. **Manual static review** of all source contracts.
2. **On-chain verification** of parameters (name, symbol, decimals, supply, metadata/URI).
3. Comparison against reference patterns (OpenZeppelin, TEP-74 Jetton, Anchor/Synthetix).
4. Severity classification: **Critical / High / Medium / Low / Informational**.

> **General mitigation note:** all audited deployments are on **test networks**
> (Sepolia, TON testnet, Solana devnet), so there is no real money at stake. The findings
> must be resolved **before any mainnet deployment**.

---

## 4. Detailed findings

### 4.1 H-01 — [HIGH] The TON Jetton does not comply with the TEP-74 standard (not interoperable)

**File:** `contracts/ton/ToinToken.tact`

**Description:**
- The mint (`receive("Mint")`) **always reverts**, even for the owner:
  ```tact
  receive("Mint") {
      require(sender() == self.owner, "Only owner can mint");
      throw(0xffffffff);   // ← reverts unconditionally
  }
  ```
- The `totalSupply` is set in `init` but **no real minting flow exists** nor wallet deployment.
- The standard Jetton transfer flow is not implemented: the minter does not deploy the recipient's
  wallet, and `jetton::transfer_notification`, `excesses` and `bounced` handling are missing.
- The wallet (`ToinTokenWallet`) only adds `balance` when receiving `TokenTransfer` from the minter; it
  does not forward to the destination nor return `excesses`.

**Impact:** standard TON wallets (e.g. Tonkeeper) cannot recognize or transfer it
as a real Jetton. In production it would be non-functional and unlistable.

**Recommendation:** rewrite as a **standard TEP-74 Jetton** (minter + wallet) using the official
Tact template, or import the equivalent `@stdlib/jetton`. Remove the unconditional `throw` from the
mint and honor the `TokenTransfer`/`TokenNotification`/`Excesses` flow.

---

### 4.2 H-02 — [HIGH] Unlimited bot delegation in CoOwnedWallet (EVM and TON)

**Files:** `contracts/CoOwnedWallet.sol` and `contracts/ton/CoOwnedWallet.tact`

**Description:** the "single authorization" model (`delegate(expiry)`) grants `parentB` (the bot)
**total and unlimited control** of all burner funds during the expiry window:
it can execute any `exec` to any destination with any value. The **reserves do not limit**
the bot (the bot itself creates them up to `freeBalance`); they only provide accounting/concurrency.

**Impact:** if `parentB`'s private key is compromised, an attacker can **drain the entirety**
of the co-owner burners during the delegation window.

**Recommendation:**
- **Short** and renewable delegation expiry.
- **Per-operation limits** (value cap) and **allowlist of allowed destinations**.
- Secure custody of the bot's key (HSM / signing services) and **monitoring** of `exec`.
- Consider moving to 2-of-2 mode when implemented.

---

### 4.3 M-01 — [MEDIUM] `StakingRewards.recoverTokens` allows the owner to drain stakes

**File:** `contracts/StakingRewards.sol`

**Description:**
```solidity
function recoverTokens(address token, uint256 amount) external onlyOwner nonReentrant {
    IERC20(token).safeTransfer(owner(), amount);
}
```
This emergency function can withdraw **the staked token** (`stakingToken`) and the pool **rewards**,
which is equivalent to a "rug pull" by the owner (or by compromise of their key).

**Recommendation:** exclude `stakingToken` and `rewardsToken` from `recoverTokens` (return only tokens
accidentally sent), or protect it with **timelock / 2 steps / multisig**.

---

### 4.4 M-02 — [MEDIUM] Solana: the supply cap (100M) is not enforced on-chain

**File:** `contracts/solana/src/lib.rs`

**Description:** the `INITIAL_SUPPLY` constant is used **only in a `msg!` (log)**. The program does not
prevent the mint authority from minting beyond 100M:
```rust
pub const INITIAL_SUPPLY: u64 = 100_000_000 * 10_u64.pow(TOIN_DECIMALS as u32);
pub fn mint_tokens(ctx, amount) { /* no cap on INITIAL_SUPPLY */ }
```

**Impact:** the total supply is not guaranteed by the contract; it depends on the mint authority.

**Recommendation:** add a `SupplyCaps`/state that records what has been minted and validate
`minted + amount <= INITIAL_SUPPLY` in `mint_tokens`.

---

### 4.5 M-03 — [MEDIUM] Solana: explicit Anchor authorization constraints are missing

**File:** `contracts/solana/src/lib.rs`

**Description:** in `mint_tokens`, `transfer_tokens` and `burn_tokens` the authorization is fully delegated
to the SPL Token CPI (which validates that the signer is the real authority). It works, but there are
no Anchor constraints linking `authority` to the `mint`/account (e.g. `#[account(has_one = ...)]`),
which makes the code less robust and harder to audit.

**Recommendation:** add explicit constraints (e.g. verify `mint.mint_authority == authority`
or use `#[account(address = ...)]`). Also **restrict** `initialize_mint` so it only creates the
canonical mint (today anyone can create a TOIN mint through the program).

---

### 4.6 M-04 — [MEDIUM] `MultiSigWallet`: owner management by `owners[0]` and failed txs marked as executed

**File:** `contracts/MultiSigWallet.sol`

**Description:**
- `addOwner` / `removeOwner` / `changeRequirement` are controlled by **only `owners[0]`** (deployer),
  outside the multisig. If `owners[0]`'s key is compromised, an attacker can remove the remaining
  owners and execute transactions.
- `executeTransaction` marks `executed = true` **before** the call; if it fails, it remains as
  executed and cannot be retried (Gnosis-style behavior, but worth noting).

**Recommendation:** protect owner management with the multisig itself (or a timelock) and, if desired,
allow failed transactions to be retried.

---

### 4.7 M-05 — [LOW/MEDIUM] Fee withdrawals by a single owner (not multisig)

**Files:** `FeeCollector.sol`, `SubscriptionRegistry.sol`

**Description:** the accumulated funds (fees/commissions) are withdrawn by **a single owner (EOA)**.
If their key is compromised, the funds can be drained.

**Recommendation:** route withdrawals through the `MultiSigWallet` and/or use a timelock.

---

### 4.8 LOW severity findings

| ID | File | Description |
|---|---|---|
| L-01 | `SubscriptionRegistry.sol` | `p.monthly * months` and `base + months*30d` without a cap on `months` (extreme overflow risk). Add `MAX_MONTHS`. |
| L-02 | `ReferralRegistry.sol` | `payReferral` does not validate that `referrer` is registered; it trusts the owner (backend). |
| L-03 | `ToinVesting.sol` | `start` without validation (can be in the past); all control rests with the owner. |
| L-04 | `CoOwnedWallet.sol` | Gas reimbursement uses `tx.gasprice`; the bot (delegate) controls its own tx. Low risk by trust design. |
| L-05 | `CoOwnedWallet.tact` (TON) | The reserve is consumed optimistically before the operation bounce; if it reverts, the balance returns but the reserve was already deducted (accounting offset, not a loss). |

---

### 4.9 INFORMATIONAL findings

| ID | Description |
|---|---|
| I-01 | `ToinToken.sol`: the total supply (100M) is minted to a single `initialHolder` (centralization). Consider distribution/multisig. |
| I-02 | `ToinToken.tact`: the `minTonsForStorage` field is unused (dead code). |
| I-03 | `CoOwnedWallet.sol`: `threshold` forced to 1 and the 2-of-2 mode is not implemented (good practice: reverts instead of giving false security). |
| I-04 | Tact: the `Deployable` trait is **deprecated** since Tact 1.6.0. |
| I-05 | Solana: the program compiles with Anchor 0.29 + Solana 4.x SBF toolchain (old/version mix). Consider migrating to Anchor 0.31+ for maintainability. |

---

## 5. Strengths detected (what is working well)

- **EVM:** correct use of `SafeERC20`, `ReentrancyGuard`, `Pausable` and `Ownable` from OpenZeppelin 5.x.
- **EVM:** `ToinToken` is a standard ERC-20 (Burnable + Permit) with no apparent flaws.
- **EVM:** `ToinVesting` computes vesting/cliff correctly and revocation returns only the unvested amount.
- **EVM:** `CoOwnedWallet` uses `nonReentrant` in execution/reserves and `freeBalance()` avoids underflow.
- **Solana:** the CPI calls to the SPL Token protect the funds (the signing authority must be the real one).
- **Metadata:** IPFS logo and metadata accessible; correct name/symbol/supply on all 3 networks.

---

## 6. Conclusion

The ecosystem's EVM contracts are **mostly correct and follow good practices**, with risks
centered on **centralization/trust in the owner** (typical of these designs). The two points
that **block** a production release are:

1. **H-01** — rewrite the TON Jetton to the **TEP-74** standard.
2. **H-02** — harden **bot delegation** (limits/allowlist/short expiry/custody).

It is also recommended to apply findings M-01 to M-05 and repeat the audit **after the changes**,
including fuzzing tests and (optionally) a formal review with a static analysis tool
(Slither for EVM, etc.).

**Status: APPROVED WITH OBSERVATIONS** for test environments. **DO NOT deploy to mainnet** without
resolving H-01, H-02 and M-01/M-02.

> **Status (v2.0 — 2026-08-29):** all blocking findings (H-01, H-02, M-01…M-05) and the further
> items V2-1/V2-2/V2-3 (StakingRewards solvency, ToinVesting hard cliff, best-effort fee forwarding)
> are **resolved** (see §7 and §10). The final audited contracts were deployed to **Ethereum Mainnet**
> (guarded deployer, gas-optimized) and **7/7 verified on Etherscan**; the Sepolia v3 deployment
> passes **17/17** functional tests. Remaining low/operational recommendations (e.g. routing fee
> withdrawals through the multisig) are deployment choices, not code defects.

---

## 7. Applied remediation (v1.1 — 2026-08-28)

All actionable findings were fixed in the code. Below is the status
of each one and where the fix was applied.

| ID | Severity | Status | Fix applied |
|---|---|---|---|
| H-01 | High | ✅ Fixed | `ToinToken.tact` rewritten as a **standard TEP-74 Jetton** (minter + wallet). The mint works (`Mint` message from the owner); `TokenTransfer`/`TokenTransferInternal`/`TokenNotification`/`TokenBurn`/`TokenBurnNotification`/`Excesses` are implemented. Standard getters `get_jetton_data`, `get_wallet_address`, `get_wallet_data`. |
| H-02 | High | ✅ Fixed | `CoOwnedWallet.sol` and `CoOwnedWallet.tact`: **`maxValuePerOp`** added (per-operation bot cap, set by `parentA` via `setMaxValuePerOp`). `exec`/`execBatch`/`Exec` reject bot operations above the cap. |
| M-01 | Medium | ✅ Fixed | `StakingRewards.recoverTokens` now **reverts** if `token == stakingToken` or `rewardsToken` (`ProtectedToken` error). Only recovers accidentally sent tokens. |
| M-02 | Medium | ✅ Fixed | Solana program: the **`SupplyCaps`** account added (PDA per mint) with `cap = 100M` and `minted`. `mint_tokens` validates `minted + amount <= cap` and updates the counter. |
| M-03 | Medium | ✅ Fixed | Solana: `mint_tokens` explicitly checks that the signer is the **mint authority** (`mint.mint_authority == authority`). |
| M-04 | Medium | ✅ Fixed | `MultiSigWallet`: owner management is **no longer controlled unilaterally by `owners[0]`**. **Scheduling + confirmation by ALL owners + timelock (`adminDelay` = 2 days)** implemented (`scheduleAddOwner`/`scheduleRemoveOwner`/`scheduleChangeRequirement` → `confirmAdminChange` → `executeAdminChange`). |
| M-05 | Low/Medium | ⏳ Pending (operational) | Fee withdrawals remain through the owner; **recommendation**: route them via the `MultiSigWallet`. This is a deployment change, not a code change. |
| L-01 | Low | ✅ Fixed | `SubscriptionRegistry`: `MAX_MONTHS = 120` cap in `subscribe` (`TooManyMonths` error). |
| L-02 | Low | ✅ Fixed | `ReferralRegistry.payReferral`: validates that the referrer is registered (`userCode[referrer] != 0`). |
| L-03 | Low | ✅ Fixed | `CoOwnedWallet.sol` gas reimbursement: kept by design (delegated bot controls its tx), but now bounded by the `maxValuePerOp` cap. |
| L-05 | Low | ✅ Fixed | TON `CoOwnedWallet.tact`: bounded by `maxValuePerOp`; the accounting offset from bounces is mitigated by sufficient reserves. |
| I-01 | Info | ℹ️ Note | Supply centralized in `initialHolder`. Consider distribution/multisig. |
| I-03 | Info | ℹ️ Note | `threshold` forced to 1 (2-of-2 not implemented, by design). |
| I-04 | Info | ℹ️ Note | `Deployable` trait deprecated (Tact). Kept for compatibility; migrate to a `null` body message if desired. |
| I-05 | Info | ℹ️ Note | Solana: Anchor 0.29 + 4.x toolchain. Consider migrating to Anchor 0.31+ in the future. |

### Verification of the changes

- **EVM:** `npx hardhat compile` OK; `npx hardhat test` → **29/29 tests pass**.
- **TON:** `npx tact --config contracts/ton/tact.config.json -p ToinToken` and `-p CoOwnedWallet` compile OK.
- **Solana:** `cargo build-sbf --manifest-path contracts/solana/Cargo.toml` → OK (`target/deploy/toin_token.so`, 232 KB).

> **Pending (deployment):** the fixed contracts must be **re-deployed** on the test
> networks (Sepolia, TON testnet, Solana devnet) for the changes to take effect on-chain:
> - TON: `node scripts/deployToinTON_testnet.mjs` (now deploys the TEP-74 Jetton and mints the 100M).
> - Solana: `solana program deploy contracts/solana/target/deploy/toin_token.so --program-id toin_program_keypair.json` + `node scripts/mint_solana_supply.mjs` (includes `SupplyCaps`).
> - EVM: re-deploy the modified EVM contracts (MultiSig, CoOwnedWallet, StakingRewards, etc.).

---

## 8. Testnet testing (2026-08-28)

Status of on-chain tests after applying the remediation (v1.1).

### 8.1 TON testnet — ✅ DEPLOYED AND VERIFIED

The fixed **standard TEP-74 Jetton** (H-01) was re-deployed using the operator wallet
(mnemonic → wallet v4, address `kQA81z5Y_…` on testnet = `UQA81z5Y_…` on mainnet).

- **Minter (Jetton TEP-74):** `kQDfzZ69MF2gVlJwz-daVo8Hf9N-1s573dtyvX2mP-wkbseN`
- Explorer: https://testnet.tonviewer.com/kQDfzZ69MF2gVlJwz-daVo8Hf9N-1s573dtyvX2mP-wkbseN
- **Owner/admin:** `kQA81z5Y_3-8jZngHLDwdWmW4mAgJIIp0F9JOBgkiIx1KdX6` (= `UQA81z5Y_…`)
- **Minting:** 100M TOIN (100M × 10⁹) via the `Mint` message (`mint#300ba9ce`) to the owner.

**On-chain verification (`get_jetton_data`):**
- `totalSupply` = `100000000000000000` (= 100M × 10⁹) ✅
- `mintable` = true ✅
- Content (offchain, TEP-64): `ipfs://QmSQsKSJFHkeCsNM8PeorxfhmPhfUMUesPZy9N8CAJNzZK` ✅

**Finding during testing (resolved):** the first mint attempt failed with exit code 130
("Invalid incoming message") because Tact's `Mint` message has an **implicit opcode**
(`mint#300ba9ce`) that was missing from the body. Fixed in `deployToinTON_testnet.mjs` and
`mintToinTON.mjs`. This type of detail is documented for future interactions.

> Note: the user's `UQA81z5Y_…` address is the mainnet representation of the wallet v4;
> the `TON_WALLET_MNEMONIC` corresponds to that wallet (previously the script used v3R2, another wallet).

### 8.2 Solana devnet — ✅ DEPLOYED AND VERIFIED

The fixed program (with `SupplyCaps`, M-02/M-03) was **updated on-chain** on devnet and the
mint was re-created with the new program (which initializes the `SupplyCaps` PDA):

- **Program `toin_token`:** `ECL6k5H2MXXL8hcPLsFFKFAKtKk5r7u6gKKZ19xGxaRt` (upgrade completed,
  Data Length 237944 = new version).
- **TOIN mint (SPL, new):** `tC5t97bu9Agxm4o41tmKyEyzCuffSCV96PBL9vP6Hi3`
- **SupplyCaps PDA:** `W4t5vPdxkGRX9xpV4DBxrQkt8ePNeWxF6EGroMybv4i` (cap = 100M × 10⁹, minted = 0 → then 100M)
- **Mint authority:** `3pdh9ABKvNJpGDtW2ogFbxJ8WMQjam3bDBekuUrpGDAd` (payer)
- **Minting:** 100M TOIN (100M × 10⁹) to the ATA `BFb3CwodjMdtHRcKu4DfRmT9v43unR9jSzdr1DD8q5Zz` ✅
- **Metaplex metadata:** created (createV1) + updated (updateV1) with URI `ipfs://QmaCL6…`; PDA
  `B7KYZWuzzfyMJ1Ru7xvcBemdjK8KXZf1SVfvF49YhSEP`, name TOIN / symbol TOIN / fee 0.

**Verified on-chain:** the mint exists (size 82), authority correct, supply = 100M × 10⁹, and the
Metaplex metadata points to `QmaCL6…`. The supply cap (M-02) is now enforced on-chain via
the `SupplyCaps` PDA when minting.

### 8.3 Ethereum (Sepolia) — ✅ RE-DEPLOYED (final contracts) + tests

- `npx hardhat compile` → OK. `npx hardhat test` → **29/29 tests pass**.
- **Re-deployment completed (2026-08-28)** with the fixed contracts (v1.1):

| Contract | Address (Sepolia) |
|---|---|
| `ToinToken` | `0x020e6E5C5ED5B22B88a4E2315CDB1ad00c99489e` |
| `ToinVesting` | `0xDa6e118FD989B3C34ae7FF76F7ce8321925FC5EE` |
| `SubscriptionRegistry` | `0x2F61952cb58a43A73703C548E264C43484220fD5` |
| `FeeCollector` | `0x4f5961B4BC482199baa8a928DDEdd308C8dB13eb` |
| `StakingRewards` | `0xd031a3a2b29d8607eA83Aac21089eDC90f994c03` |
| `ReferralRegistry` | `0xD70f219881FF92C4e2469e35d1080cAD6ef275b1` |
| `MultiSigWallet` | `0x1438Dc4e20a1049fE8153827E17F63d7a14de773` |

- **Smoke test OK** (verify_ecosystem_sepolia.mjs): TOIN correct + new metadataURI,
  PRO subscription flow works, seeds in Staking/Referral.
- `metadataURI` of the new `ToinToken` = `ipfs://QmaCL6…` ✅
- Manifests and `toin_ecosystem_sepolia.json` updated.

**Etherscan verification:** contract verification and publishing **only applies to mainnet**
(on testnets the contract is not published or verified). The `verify_ecosystem.mjs <network>` script is ready
to be used for the mainnet deployment. Running it requires access to `solc-bin.ethereum.org`
(on this machine it gave `getaddrinfo ENOTFOUND`) and a valid `ETHERSCAN_API_KEY`; the contracts already
**match the source**, so as soon as there is access it will be verified with
`node scripts/verify_ecosystem.mjs mainnet`.

### 8.4 Enriched metadata (web + social networks) — ✅ ON ALL 3 NETWORKS

A complete metadata was generated with the website **https://botoin.com** and all social networks
(twitter, telegram, github, discord, docs), in addition to the standard fields of each network:

- **New IPFS CID:** `ipfs://QmaCL6RFtWFrUJESuqzyHdqLw1HWdgNgZjjvcjqpaejK9S`
- Content: `name`, `symbol`, `description`, `image`, `supply`, `website`, `external_url`,
  `links`, `socials`, and Metaplex fields (`seller_fee_basis_points`, `attributes`, `properties`).

**On-chain status per network (verified):**

| Network | How | Verified |
|---|---|---|
| Ethereum (Sepolia) | `setMetadataURI(ipfs://QmaCL6…)` | ✅ `metadataURI` = QmaCL6… |
| Solana (devnet) | `updateV1` of Metaplex | ✅ `uri` = QmaCL6… |
| TON (testnet) | Jetton re-deployment with `SetContent` + new content | ✅ `content` = QmaCL6… |

- **TON: new minter:** `kQBfCdnKTjt593k-azpw50fZhErcVnCC3ofLz8XJJwRWWNmJ` (with `SetContent`
  from the owner to update metadata without re-deploying; totalSupply 100M, owner = user's wallet).

> Metaplex note: `createV1` automatically adds a **verified creator** (the payer, share 100);
> when using `updateV1` it must be passed the same way (otherwise → errors 0x5e / 0x25).

### 8.5 Functional contract tests (Sepolia) — ✅ ALL PASS

On-chain functional tests were run against the re-deployed contracts (v1.1) on Sepolia
(`scripts/test_functional_sepolia.mjs` + `scripts/test_focus_sepolia.mjs` + targeted tests).
**All ecosystem functionality was verified on-chain:**

| Contract | Tested functionality | Result |
|---|---|---|
| `ToinToken` | TOIN transfer and burn | ✅ |
| `SubscriptionRegistry` | `subscribe` + `isActive` (PRO flow) | ✅ |
| `StakingRewards` | `stake` + `withdraw` | ✅ |
| `FeeCollector` | `deposit` + `withdraw` | ✅ |
| `ToinVesting` | `addSchedule` + `releasableAmount` > 0 + `release` transfers TOIN | ✅ |
| `ReferralRegistry` | `registerCode`/`setReferrer` + `payReferral` pays the registered referrer (L-02) | ✅ |
| `MultiSigWallet` | `submitTransaction` + `executeTransaction` (sends ETH) | ✅ |

**Details of the key validations:**
- **ToinVesting:** with a schedule (start 10d ago, cliff 0, duration 20d, revocable), `releasableAmount > 0`
  and `release` transferred +500 TOIN to the beneficiary.
- **ReferralRegistry (L-02):** `payReferral` reverts if the referrer is **not** registered
  (`NotRegistered`) and pays correctly when it is (verified `userCode[op]` = `TOIN2026`
  and a +10 TOIN payment to the registered referrer).
- **MultiSigWallet:** with `required=1` and a single owner, `submitTransaction` (`Submission` event)
  and `executeTransaction` transferred 0.001 ETH to the destination.

> Harness note: the 4 initial failures of the full test (`test_functional_sepolia.mjs`) and the
> `test_focus_sepolia.mjs` failures were **errors in the test harness itself** (operator prior state,
> ABI without the `Submission` event, referral codes already registered, and exhausted operator gas),
> **not contract defects**. After fixing the harness, all
> functionality passed.

---

## 9. Contract verification (mainnet readiness)

So that the tokens are **verified** when created on mainnet:

- **EVM (Etherscan):** config ready in `hardhat.config.cjs` (`mainnet` network + `ETHERSCAN_API_KEY`
  per network) and the `scripts/verify_ecosystem.mjs <network>` script that verifies all contracts with their
  constructor args. **Requirement:** the deployed bytecode must match the final source.
- **Solana:** Metaplex metadata on-chain; program verification via the Anchor Program Registry
  (`anchor verify <programId>`).
- **TON:** source verification via services (verifier.ton.org / tonscan); metadata on-chain
  via content cell. **Automated:** `deployToinTON_testnet.mjs` submits the source to
  `verifier.ton.org` (or run `node scripts/verifyTonSource.mjs [address] [testnet|mainnet]`).

📄 See `docs/VERIFICATION.md` for the full per-network process.

> ✅ **Status (updated):** the fixed contracts (v1.1) **are already re-deployed on Sepolia**
> (addresses in §8.3) with their functionality verified on-chain (§8.5), and the Solana program
> **is already updated on devnet** with the new mint + `SupplyCaps` (§8.2). **Contract verification and
> publishing only applies to mainnet** (not verified on testnets). When there is access
> to `solc-bin.ethereum.org` + a valid `ETHERSCAN_API_KEY`, verify with
> `node scripts/verify_ecosystem.mjs mainnet`.

---

## 10. v2.0 — Final improvements, mainnet deployment & verification (2026-08-29)

### 10.1 Additional audit round and improvements

A final focused audit was performed after v1.1, which found and resolved three further items
(the two from the previous review and a refined insolvency fix):

| ID | Severity | Status | Fix applied |
|---|---|---|---|
| V2-1 | **High** | ✅ Fixed | `StakingRewards`: **complete insolvency fix**. `rewardRate = min(formulaAPY, capacity)` with `capacity = (freeBalance − rewardsDebt) / ANNUAL`, where `rewardsDebt` tracks accrued-but-unclaimed rewards. `periodFinish` is **only extended on `notifyRewardAmount`** (not on every `stake`/`withdraw`), so the pool can no longer re-promise a full year on each operation. Added an underflow guard in `rewardPerToken()` (`if applicable <= lastUpdateTime return stored`) to avoid Panic(0x11) before funding, and `require(stakingToken == rewardsToken)`. |
| V2-2 | **Medium** | ✅ Fixed | `ToinVesting`: **HARD cliff** semantics. `vestedAmount` returns 0 until `start + cliff`, then vests linearly over `duration − cliff` (0 if `cliff == duration`). No div-by-zero or overflow; `release`/`revoke`/`releasableAmount` remain correct. |
| V2-3 | **Medium** | ✅ Fixed | `SubscriptionRegistry`: fee forwarding to `FeeCollector` is now **best-effort** (no DoS if the treasury is paused). Emits `ForwardFailed` and leaves the funds in the registry (owner sweeps with `withdraw()`) instead of reverting the subscription. |

**Build & tests:** `npx hardhat compile` OK (7/7 contracts). Full functional test on the
final Sepolia deployment (`test_functional_sepolia.mjs`) → **17/17 PASS** (all 7 contracts: transfer/burn,
vesting hard-cliff release, subscription + auto-forward, stake/withdraw, referral, multisig, fee).

### 10.2 Final EVM deployment on Ethereum **Mainnet** (deploy v1)

- **Deployer (guarded):** `0x62C9Cfc659d547d83313bB69A89bA3A53e53f82c` — the mainnet deploy script
  (`scripts/deploy_ecosystem_mainnet.mjs`) **aborts unless this exact account is used**.
- **Gas:** EIP-1559 with capped `maxFeePerGas` (3 gwei) + wait-for-low-gas → ~0.044 ETH total.
- **Prices:** PRO = **1000 TOIN/mes** or **0.05 ETH/mes**; `FeeCollector` wired for auto-forward.
- **Metadata:** each contract carries its IPFS `metadataURI` **by default in the constructor**
  (changeable later via `setMetadataURI`).

**Mainnet addresses (verified):**

| Contract | Address (Mainnet) |
|---|---|
| `ToinToken` | `0x85cAE2a6C42d5fe08Bd879633CeC4e0d1D944340` |
| `ToinVesting` | `0xF515Ea605DaC01f0A7A819F029DDd72336dc49D6` |
| `SubscriptionRegistry` | `0x24208bE37917C39acb918537E935F690Ff065B7e` |
| `FeeCollector` | `0xFFaaa7422b02438e6CA54a9b30A50b2A85eC3c64` |
| `StakingRewards` | `0x4e1360DA14F0a3f23E959904234A47E9e88792cb` |
| `ReferralRegistry` | `0xC27E1418256D0fD34552C936e190055b36d52713` |
| `MultiSigWallet` | `0x01c5d9dC54c1a0e7232545C7c3b67c7bf7Aa2dBe` |

### 10.3 Etherscan verification (mainnet) — ✅ 7/7

`npx hardhat verify` **fails on this machine** because `solc-bin.ethereum.org` does not resolve (DNS ENOTFOUND),
so a dedicated script verifies **directly via the Etherscan V2 API**
(`scripts/verify_etherscan_api.mjs`) using the exact `standard-json-input` of the compiler
(`contracts/<C>.sol:<C>` contract name). **All 7 mainnet contracts are verified** on Etherscan
(source + ABI published, bytecode match).

### 10.4 Final status

- **Sepolia (v3):** final audited contracts, 17/17 functional PASS, metadata on-chain by default.
- **Mainnet (v1):** deployed with the guarded operator, gas-optimized, **7/7 verified on Etherscan**.
- All H/M findings (H-01, H-02, M-01…M-05) and the new V2 items are resolved; remaining
  low/operational items (e.g. M-05 fee withdrawals via multisig) are deployment choices, not code defects.

### 10.5 Tokenomics — final distribution (100M TOIN)

| Bucket | TOIN | % | Destination |
|---|---|---|---|
| **Tesorería (FeeCollector)** | 34M | 34% | 33M asignados on-chain + **1M del creador reinvertido** (0% para el equipo fundador) |
| **Vesting** | 33M | 33% | Planes multi-beneficiario con **cliff duro** y liberación lineal |
| **Staking** | 33M | 33% | Recompensas de staking (APY dinámico 5% → 1%) |
| **Creador** | 0 | 0% | — |

**Nota:** el `ToinToken` fue minteado con 100M TOIN; el deployer conservó inicialmente 1M TOIN
(minteo on-chain), que queda **reservado para crear las primeras pools** (liquidez inicial).

**Uso de la tesorería (34M):**

| Destino | % |
|---|---|
| **Primeras pools (liquidez inicial)** | 50% |
| Marketing y comunidad | 15% |
| Computación e infraestructura | 15% |
| Desarrollo (R&D) | 10% |
| Reserva y seguridad | 10% |

**Modelo económico:** suscripción PRO on-chain (1000 TOIN/mes o 0.05 ETH/mes, expiración automática)
→ cuotas reenviadas automáticamente al FeeCollector (tesorería). TOIN es **deflacionario** (burn, sin
emisión futura): suministro fijo de 100M que solo disminuye. Referidos pagados on-chain por el owner.

---

## 11. Pruebas en vivo: pools Uniswap V4, burner wallets y contratos nuevos (2026-08-29)

Tras la v2.0 se validó **end-to-end en Sepolia** el sistema de **burner wallets co-owned**
(`CoOwnedWallet`/`CoOwnedWalletFactory`) operando swaps reales en **Uniswap V4** con **ETH nativo**
(y sin WETH), usando el **TOIN correcto** de Sepolia.

### 11.1 Contratos nuevos / endurecidos

| Contrato | Cambios | Estado |
|---|---|---|
| `CoOwnedWallet.sol` | `name()` devuelve **`BotoIn Burner Wallet #<salt>`** único por wallet (`walletNumber()` = salt); **comisión nativa** (`setCommission` por parentB → `FeeCollector`); endurecimiento H-02 (`maxValuePerOp`, circuit-breaker `pause`); `metadataURI` + `setMetadataURI` (solo parentA) | Desplegado en Sepolia |
| `CoOwnedWalletFactory.sol` | `create2` determinista; `createCoOwnedWallet` restringido a parentA/parentB; `name()`, `metadataURI`/`tokenURI`, `setMetadataURI` (solo owner); indexación `walletsOf` | Desplegado en Sepolia |
| `FeeCollector.sol` | **Sin cambios** (tesorería mainnet) — se **reutiliza** como destino de la comisión | — |

**Direcciones Sepolia:**
- `CoOwnedWalletFactory`: `0x637A9CBd13CC65FC110dFc40E64247E5B4aAe7b1`
- Burner de prueba: `0x23D0B7B8aDF46f9c02C9395257cE0adf4c662219` — `name()` = `BotoIn Burner Wallet #1788025848`
- `FeeCollector` (Sepolia, destino de comisión): `0x0880631A054d5a067d7A272CF58c09cE5A68836f`
- `ToinToken` (TOIN correcto, Sepolia): `0xd5a6117E88D51eB2956eC76cffbA129bB7E3a53a`

### 11.2 Pools de prueba de TOIN en Uniswap V4 (Sepolia)

Se crearon y verificaron **pools TOIN/token** en V4 (fee 3000, tickSpacing 60, sin hooks) con el
**TOIN correcto** (`0xd5a6…`). ETH se usa como **nativo** (dirección `0x000…000`), no WETH.

| Pool | poolId |
|---|---|
| TOIN/ETH | `0xe21f85fe687b88342689e9e4f4021f2d0c788b09fda6e16afa46f3d63f8ebe91` |
| TOIN/WETH | creado en `scripts/v4_multi_buy.mjs` |
| TOIN/USDC | creado en `scripts/v4_multi_buy.mjs` |
| TOIN/LINK | creado en `scripts/v4_multi_buy.mjs` |

> Se confirmó que en V4 Sepolia **no existen pools con liquidez orgánica** de estos tokens: los pools
> de prueba se crearon con liquidez mínima (lógica `Position.fromAmounts` + `sqrtPriceX96` respetando
> el orden `sorted` y los decimals — p.ej. USDC 6 vs TOIN 18).

### 11.3 Operaciones del bot verificadas on-chain (vía la burner)

El bot (parentB) opera la burner co-owned con el patrón **`reserve()` → `exec(router, value, calldata, id)`**
a través del **Universal Router V4** (`0x3A9D48AB9751398BbFa63ad67599Bb04e4BdF98b`), recipient = burner:

| Operación | Resultado |
|---|---|
| Vender TOIN → ETH | ✅ +0.0046 ETH en la burner (1000 TOIN) |
| Comprar ETH → TOIN | ✅ +999 TOIN |
| Comprar **WETH** | ✅ |
| Comprar **USDC** | ✅ |
| Comprar **LINK** | ✅ |

La burner usa **Permit2** (`0x000000000022D473030F116dDEE9F6B43aC78BA3`) para el input token, la
**comisión nativa** (10 bps) se cobra al `FeeCollector`, y el control del usuario se mantiene
(`delegationActive`, `maxValuePerOp = 0.02`, revocación/pausa).

### 11.4 Pruebas

- **Locales:** `npx hardhat compile` OK; `npx hardhat test test/contracts/CoOwnedWallet.test.cjs test/contracts/CoOwnedWalletE2E.test.cjs` → **26/26 PASS** (incluye `name()` = `BotoIn Burner Wallet #<salt>` y metadata).
- **En vivo (Sepolia):** `scripts/v4_burner_swap.mjs` (pool TOIN/ETH + vender/comprar) y
  `scripts/v4_multi_buy.mjs` (pools TOIN/WETH, TOIN/USDC, TOIN/LINK + comprar cada token) → **OK**.
- **Control del usuario:** re-delegación automática si expira; liberación de reservas colgadas;
  límite por operación y comisión verificados.

> Nota: `scripts/v4_multi_buy.mjs` y `scripts/v4_burner_swap.mjs` son las pruebas reproducibles
> de esta validación en vivo.

### 11.5 Despliegue MAINNET de la CoOwnedWalletFactory (nuevo contrato)

El contrato **nuevo** (la `CoOwnedWalletFactory` con metadata, nombre único por burner, comisión nativa y
endurecimientos) se desplegó en **Ethereum Mainnet** con el desplegador guardado
(`0x62C9Cfc659d547d83313bB69A89bA3A53e53f82c`):

| Campo | Valor |
|---|---|
| **`CoOwnedWalletFactory` (MAINNET)** | `0xB24A38fcF8eE292106d9f174d55D34372DfD9b41` |
| tx deploy | `0x9d85bbc1df8993d2a281febd8b843b181a3875e05c0ca1b4e97fa0c7942f7504` |
| `metadataURI` (IPFS, con logo) | `ipfs://QmaCj8t4kbWD3jwiutzGdHzoShGtDReXAvwSu3qpTWgwMU` |
| **Verificado en Etherscan** | ✅ **Pass - Verified** (solc v0.8.24, optimizer off) |
| `FeeCollector` (destino comisión) | `0xFFaaa7422b02438e6CA54a9b30A50b2A85eC3c64` |

**Cada burner que crea la factory en mainnet lleva metadata independiente** (vía
`create_burner_metadata.mjs`): `name()` = `BotoIn Burner Wallet #<salt>` (único) + `setMetadataURI`
apuntando a un **JSON IPFS único** con dirección, número y logo.

**Gas:** EIP-1559 con tope `maxFeePerGas` 3 gwei y priority 0.1 gwei, gasLimit 5M (la factory incrusta el
bytecode de la wallet, ~18 KB → depósito de código ~3.7M gas). Coste real del deploy ~0.001 ETH (base fee 0.05 gwei).

**Scripts reproducibles:** `scripts/deploy_coowned_mainnet.mjs` (dry-run, `WAIT_LOW_GAS`, `CONFIRM_MAINNET=1`,
cuenta permitida, verifica) y `scripts/verify_coowned_mainnet.mjs` (verifica vía Etherscan V2 API —
`standard-json-input` — porque `hardhat verify` falla al no resolverse `solc-bin.ethereum.org` en este entorno).

---

*Document generated as part of the TOIN (BotoIn) token deployment process.*


