Deploy — Testnet (Polygon Amoy)
This guide gets Sylan’s contracts live on Polygon Amoy (80002), wires modules together, and performs a smoke test. It assumes you’re using Node 18+, pnpm, and Hardhat (or Foundry with equivalent steps). Final addresses must be copied to Architecture → Addresses & ABIs.
All core contracts are UUPS proxies. Always interact with the proxy addresses.
0) Prerequisites
- Wallet with Amoy MATIC for gas (fund a deployer and a test user)
- RPC URL for Amoy (e.g., Alchemy/Infura/Ankr)
pnpm,hardhat,typescriptin your dev env
Install deps:
pnpm i1) Environment
Create .env at repo root:
# Deployer
PRIVATE_KEY=0xabc... # test key only
# Polygon Amoy
AMOY_RPC_URL=https://polygon-amoy.g.alchemy.com/v2/xxxxxxxx
POLYGONSCAN_API_KEY=xxxxxxxx
# Optional: initial params
PLATFORM_TREASURY=0x1111111111111111111111111111111111111111
NODE_POOL=0x2222222222222222222222222222222222222222
TREASURY=0x3333333333333333333333333333333333333333Hardhat config (example network stanza):
networks: {
amoy: {
url: process.env.AMOY_RPC_URL!,
accounts: [process.env.PRIVATE_KEY!],
chainId: 80002,
},
}2) Build & test locally
pnpm hardhat compile
pnpm hardhat test3) Deploy order (recommended)
- SylanToken (ERC‑20, UUPS)
- EventLogger (UUPS)
- NodeRegistry (UUPS)
- APIEscrow (UUPS)
- APIConsensus (UUPS)
- AccessRegistry (UUPS)
- SylanStaking (optional, UUPS)
- SylanVesting (optional, non‑upgradeable)
- PresaleContract (optional, UUPS)
If you use a single script, deploy in this order and then wire addresses (next step).
4) Wiring (post‑deploy)
Run an admin script (or Hardhat tasks) to connect modules:
// pseudo‑code outline
escrow.setPlatformTreasury(PLATFORM_TREASURY)
escrow.setNodePool(NODE_POOL)
escrow.setAccessRegistry(accessRegistry.address)
escrow.setApiConsensus(consensus.address)
escrow.setNodeRegistry(nodeRegistry.address)
consensus.setQuorum(3) // example
consensus.setRequestExpiryGraceMs(120_000) // 2 minutes
accessRegistry.setApiEscrow(escrow.address)
accessRegistry.setApiConsensus(consensus.address)
accessRegistry.setNodeRegistry(nodeRegistry.address)
accessRegistry.setMaxRequestExpiryMs(60_000) // 60s cap
nodeRegistry.setTreasury(TREASURY)
nodeRegistry.setNodePool(NODE_POOL)
nodeRegistry.setSlashDistribution(5000, 4000, 1000) // 50/40/10 bpsGrant roles:
// If staking will mint rewards
await sylanToken.grantRole(MINTER_ROLE, sylanStaking.address)
// If staking won’t mint, pre‑fund rewardSource and set allowanceUse a multisig as owner where possible, even on testnet.
5) Verify on Polygonscan
pnpm hardhat verify --network amoy <impl_or_proxy_addr> <constructor/initializer args if any>- For UUPS proxies, verify implementation contracts and then mark the proxy as an EIP‑1967 proxy if your explorer supports it.
6) Seed test data
6.1 Fund testers with SYL
// From deployer/admin
await sylanToken.mint("0xTester", ethers.parseUnits("100000", 18))6.2 Register a sample API
const apiId = ethers.id("sample:price-feed:v1") // 32‑byte id
await accessRegistry.registerApi(
apiId,
providerOwner,
providerSigner,
/*seqMonotonic=*/true,
/*maxSkewMs=*/ 5000,
/*maxTtlMs=*/ 60000,
{
accessType: 1, // PayPerCall
price: ethers.parseUnits("12", 18),
duration: 0, // PPC
callLimit: 0,
active: true,
}
)
await accessRegistry.setDescriptor(apiId, "ipfs://CID", "0xcontenthash...")6.3 Register a node (optional for eligibility)
await sylanToken.approve(nodeRegistry, ethers.parseUnits("1000",18))
await nodeRegistry.registerAndStake(ethers.parseUnits("1000",18), testerPayout, "node‑amoy‑1")7) Smoke test (PPC)
- Approve & lock
// tester wallet
await sylanToken.approve(escrow, ethers.parseUnits("12",18))
const payload = { path: "/v1/price", query: { symbol: "BTC" } }
const requestHash = keccak256(toHex(JSON.stringify(payload)))
const expiresAtMs = BigInt(Date.now() + 60_000)
const tx = await escrow.lockForCall(apiId, requestHash, expiresAtMs)
const receipt = await tx.wait()- Submit snapshots (node)
// Node submits provider‑signed Snapshot via consensus.submitSnapshot(...)- Finalize → settle
- Watch
APIConsensus.RequestFinalizedthenAPIEscrow.Settled. - Check balances with
escrow.withdrawableOf(account); callwithdraw().
8) Upgrade rehearsal (optional)
- Deploy
v2implementations to Amoy. - Execute
upgradeToAndCallwith areinitialize(2)payload on a non‑critical contract. - Confirm state preservation and new behavior.
Troubleshooting
- Insufficient allowance/approve: ensure SYL
approve(orpermit) occurred beforelockForCall/purchaseSubscription. - revert BPS sum: provider/node/platform BPS must sum to 10,000 when setting fees.
- InactiveAPI: confirm
AccessRegistry.isApiActive(apiId)is true. - Signer 0x0: if signer timelock is enabled,
providerSignerOf(apiId)returns0x0until the window elapses. - Proxy verification: verify implementation first; explorers then recognize the proxy automatically.
Copy‑paste task list
- Fund deployer & tester with Amoy MATIC
- Set
.env(RPC, PRIVATE_KEY, API keys) - Deploy in order (Token → Logger → NodeRegistry → Escrow → Consensus → Registry → optional contracts)
- Wire addresses & parameters
- Verify on Polygonscan
- Seed: mint SYL, register API, stake a node
- Smoke test PPC flow
Last updated on