Documentation

Protocol Reference

Everything a builder, integrator or auditor needs.

Technical reference · English

1 · Overview

Eternal Force is a non-custodial matrix protocol on BNB Smart Chain, written in Solidity ^0.8.20 (compiled with 0.8.24, optimizer 200 runs, EVM paris). It combines two board shapes across 12 price levels that double each step:

  • S6 — a 2×2 board with 6 seats (levels 1, 2, 4, 5, 7, 8, 10, 11)
  • S3 — a 1×3 board with 3 seats (levels 3, 6, 9, 12)

All values are denominated in USDT (BEP-20). Every payment is executed inside the same transaction that triggers it: the contract's USDT balance is always 0 between transactions. The only amount ever held is the auto-upgrade escrow of active users, and that balance is spent in the same transaction in which it is created whenever it reaches the next level's price.

The constructor registers msg.sender as User #1 with all 12 levels pre-activated and referrer = address(0). Any payment that cannot be routed to a valid recipient falls back to User #1, so funds can never become stranded.

2 · Addresses

NetworkContractUSDT
BNB Smart Chain (mainnet, 56) — paste after deploy — 0x55d398326f99059fF775485246999027B3197955
BSC Testnet (97) — paste after deploy — 0x337610d27c682E347C9cD60BD4b3b107C9d34dDd

Deployed addresses are printed by scripts/deploy.js and saved to deployments/<network>.json. Also paste them into site/js/config.js so the dApp knows where to look.

3 · Level schedule

Fixed on-chain — no owner function can change a price.

LevelPrice (USDT)Board
0120S6
0240S6
0380S3
04160S6
05320S6
06640S3
071,280S6
082,560S6
095,120S3
1010,240S6
1120,480S6
1240,960S3

4 · Payout routing

When a participant pays for level L, the USDT transfer is split by the seat that the pay-er occupies in their own board of L:

S6 board (6 seats)

SeatRecipient
1 – 2Nearest qualified upline holding level L (spillover walks up)
3The pay-er (board owner), 100%
4 – 5Auto-upgrade escrow of the pay-er (or pay-er directly with a 25% fee when auto-upgrade is off)
6Recycle payment: opens the next cycle for the pay-er + pays the current cycle's sponsor

S3 board (3 seats)

SeatRecipient
1 – 2The pay-er (board owner), 100% → also feeds auto-upgrade escrow
3Recycle payment: opens the next cycle + pays the current cycle's referrer

All outbound transfers emit PaymentSent(payer, recipient, amount, level, position, reason) where reason ∈ {0: Placement, 1: AutoEscrow, 2: AutoPenalty, 3: Orphan, 4: EscrowRefund}.

5 · Placement & spillover

Placing a new member (or a downgraded matrix slot) follows depth-first spillover:

  1. Try the referrer's own board at this level: first free seat row by row.
  2. If full, descend into existing members' boards (row order), bounded by MAX_RECURSION_DEPTH = 20.
  3. If the referrer chain is exhausted or invalid, walk up the pay-er's upline via findQualifiedUpline (also capped at 20 steps).
  4. If nothing qualifies, the participant is attached to User #1 and the event is flagged orphan = true — the payment still succeeds.

Every placement emits Spillover(placedUser, level, matrixOwner, position, orphan).

6 · Auto-upgrade escrow

  • autoUpgradeEnabled defaults to true and is stored per user (setAutoUpgrade(bool)).
  • Designated escrow seats: S6 → seats 4–5, S3 → seats 1–2.
  • While enabled, those seats credit autoUpgradeEscrow[level] instead of paying out.
  • Whenever escrow[next] ≥ price(next) the next level is purchased automatically in the same transaction (the contract already holds the money), emitting Upgrade(..., autoTriggered = true).
  • While disabled, designated seats pay the user immediately with a 25% protocol fee sent to productFund() — the user keeps 75%.
  • Disabling never strands money: remaining escrow is refundable (EscrowRefund) via the contract's rescue path for the user's own balance.

7 · Recycle

When the final seat of a board fills, the recycle payment is made, then reinvestCount++, all seat arrays are cleared and currentReferrer is re-derived for the new cycle. Recycle(user, level, cycle) is emitted. The board is immediately ready for a fresh fill — loops never grow unbounded.

8 · Events

event Registration(address indexed user, address indexed referrer, uint256 indexed userId);
event Upgrade(address indexed user, uint8 indexed level, uint256 cost, bool autoTriggered);
event Recycle(address indexed user, uint8 indexed level, uint256 cycle);
event Spillover(address indexed placedUser, uint8 indexed level,
                address indexed matrixOwner, uint8 position, bool orphan);
event PaymentSent(address indexed payer, address indexed recipient, uint256 amount,
                  uint8 indexed level, uint8 position, uint8 reason);
event AutoUpgradeChanged(address indexed user, bool enabled);

9 · Functions

Write

FunctionNotes
register(address referrer)Requires levelPrice(1) in USDT (approve first). address(0) or unknown referrer ⇒ User #1. One-time.
activateLevel(uint8 level)Requires USDT levelPrice(level) and level-1 active (level 1 only for new users).
setAutoUpgrade(bool)Per-user escrow switch; emits AutoUpgradeChanged.
setMatrixBlocked(uint8, bool)Pauses a user's own board (owner/authorized path only).
rescueForeignToken(address token, address to)Can never move USDT or the accepted payment token — guarded.

Read

FunctionReturns
registered(address)bool
getUser(address)(id, referrer, partnersCount, autoUpgrade)
getMatrix(address, uint8)(currentReferrer, blocked, cycle, first[2], second[4], s3[3])
isLevelActive(address, uint8)bool
getEscrow(address, uint8)uint256 (auto-upgrade piggy bank)
levelPrice(uint8) / isS6Level(uint8)schedule helpers
userCount() / user1Address() / productFund() / usdt()protocol state

10 · Integration

Minimal ethers v6 example:

import { Contract, BrowserProvider } from "ethers";

const abi = [
  "function register(address referrer)",
  "function activateLevel(uint8 level)",
  "function setAutoUpgrade(bool enabled)",
  "function registered(address) view returns (bool)",
  "function getUser(address) view returns (uint256,address,uint256,bool)",
];

const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const ef = new Contract(CONTRACT_ADDRESS, abi, signer);

await usdt.approve(CONTRACT_ADDRESS, price);   // once per amount
await ef.register(referrer);                   // level 1 = 20 USDT

A ready-made front-end exists in site/ (pure static files, ethers loaded from CDN, 6 languages) and can be dropped onto Vercel or Netlify as-is.

11 · Deploy & verify

npm install
npm.cmd run compile
npm.cmd run test              # 25/25 suite
npm.cmd run deploy:testnet    # BSC testnet
npm.cmd run deploy:mainnet    # BSC mainnet (requires .env PRIVATE_KEY)

Then verify on BscScan with the printed arguments, and paste the resulting address into site/js/config.js. See the project README.md for the full checklist (gas funding, .env, verification command).

12 · Security notes

  • OpenZeppelin v5: SafeERC20, ReentrancyGuard, Ownable.
  • Checks → effects → interactions ordering; state (seats, cycle counters) is updated before every external transfer.
  • Bounded loops: placement recursion ≤ 20, upline walk ≤ 20 — predictable gas.
  • $0 custody invariant: asserted by the test suite — contract balance is 0 after every scenario except mid-transaction escrow.
  • No price/ownership migration: level prices are pure functions; the owner cannot alter user funds.
  • Test suite: 25 tests covering registration, routing, spillover, orphan fallback, auto-upgrade on/off, penalties, recycle cycles and the $0 invariant.

Disclaimer: this documentation describes software provided as-is, without warranty. It is not financial advice. Matrix structures carry risk and may be regulated in your jurisdiction — participants are responsible for their own compliance and decisions.