Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Credit-gated API relay for AI model access with Ethereum auth and usage metering
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Stake DIEM tokens to earn USDC yield from Venice AI compute revenue. All staked DIEM is forward-staked on Venice for compute credits, and revenue flows back to stakers as USDC. An optional auto-compounding wrapper (csDIEM) re-invests USDC rewards back into DIEM via on-chain swap.
Live at diem-relay.com. Deployed on Base. Built with Foundry (Solidity 0.8.24).README 전문 보기 ↗Stake DIEM tokens to earn USDC yield from Venice AI compute revenue. All staked DIEM is forward-staked on Venice for compute credits, and revenue flows back to stakers as USDC. An optional auto-compounding wrapper (csDIEM) re-invests USDC rewards back into DIEM via on-chain swap.
Live at diem-relay.com. Deployed on Base. Built with Foundry (Solidity 0.8.24).
sDIEM v2 (transferable ERC-20 + EIP-2612 permit, Synthetix rewards checkpointed on every transfer) and csDIEM v2 (canonical ERC-4626 wrapper over sDIEM v2, with synchronous standard redeem) are live on Base. The two contracts together enable composability with Pendle SY, Morpho/MetaMorpho, Spectra IBT, and Silo without bespoke adapters. The Pashov audit fixes from csDIEM v1 (caller-supplied harvest deadline, mandatory minDiemPerUsdc floor, uint128 bound on the TWAP input) are carried forward verbatim.
Live addresses (Base):
0x8065228a8156590A8BFca30678394e9db91f80Ee0x78B8726929911044748374178CB2D417A54319e50x01Ea790410D9863A57771D992D2A72ea326DD7C9 (same as v1)Migration story: v1 LPs exit v1 via requestWithdraw → 24h → completeWithdraw (or requestRedeem → completeRedeem for csDIEM v1) and then deposit into v2. The 24h friction is unavoidable — DIEM has to round-trip through the Venice cooldown. No on-chain migrator contract is shipped; the LP set is small enough to coordinate off-chain.
┌──────────────────────────────┐
│ Venice AI Compute │
└──────────────┬───────────────┘
│ USDC revenue
▼
┌──────────────────────────────┐
│ RevenueSplitter │
│ Receives USDC from customers│
│ 20% → platform Safe │
│ 80% → sDIEM stakers │
│ Permissionless distribute() │
└──────┬─────────────────┬─────┘
20% │ 80% │ notifyRewardAmount()
▼ ▼
┌──────────┐ ┌──────────────────┐ ┌────────────────────────┐
│ 2/2 Safe │ │ sDIEM │←───│ csDIEM │
│ (platform│ │ Synthetix fork │ │ ERC-4626 wrapper │
│ fees) │ │ Earn USDC (24h) │ │ harvest() compounds │
└──────────┘ └──────────────────┘ │ USDC → DIEM via │
│ Slipstream CL │
└────────────────────────┘
| Contract | Description |
|---|---|
| sDIEM | Synthetix StakingRewards fork. Stake DIEM, earn USDC rewards streamed linearly over 24h. All staked DIEM is forward-staked on Venice for compute credits. 24h async withdrawals matching Venice's unstake cooldown. |
| RevenueSplitter | Receives USDC revenue from compute customers and splits it 20% to the platform 2/2 Safe and 80% to sDIEM stakers via notifyRewardAmount. Permissionless distribute() with a 23h cooldown and minimum-amount floor to prevent reward-stream fragmentation. |
| csDIEM | ERC-4626 auto-compounding wrapper over sDIEM. Deposit DIEM → csDIEM stakes it into sDIEM → permissionless harvest() claims accrued USDC, swaps to DIEM via Aerodrome Slipstream CL with TWAP-protected slippage, restakes. Yield compounds in DIEM rather than streaming as USDC. Standard ERC-4626 withdraw/redeem are disabled — exits use the async requestRedeem → 24h delay → completeRedeem flow. |
| DIEMVault | USDC deposit vault for the DIEM Relay service. Borrowers deposit USDC on-chain; an off-chain watcher credits relay accounts. Deposit-only (Phase 1). |
sDIEM v2 (0x8065…80Ee) | ERC-20 + EIP-2612 permit. Same Synthetix reward model and Venice forward-staking as v1, but transferable. The reward checkpoint is hooked into the OZ v5 _update hook so balance changes (mint/burn/transfer) re-snapshot user accruals — preventing the Synthetix-ERC20 reward-leak trap. The 24h withdrawal queue is per-address and does not transfer with sDIEM. |
csDIEM v2 (0x78B8…19e5) | Canonical ERC-4626 wrapper over sDIEM v2. asset() is sDIEM v2 (not DIEM). Standard sync redeem works; maxRedeem/maxWithdraw return real values — composable with Pendle, Morpho, Spectra, Silo. depositDIEM zap handles users holding raw DIEM. recoverERC20 blocks DIEM, USDC, and sDIEM. Pause gates deposits and harvest; redemptions are always allowed. |
Stake DIEM → sDIEM
→ forward-staked on Venice ($1/day compute per staked DIEM)
→ compute revenue lands on RevenueSplitter as USDC
→ distribute(): 20% → 2/2 Safe, 80% → sDIEM.notifyRewardAmount()
→ streamed to stakers over 24h
Optional: deposit DIEM into csDIEM instead
→ csDIEM forwards to sDIEM (same Venice forward-stake)
→ harvest(): claims USDC reward stream → swaps via Slipstream CL → re-stakes in sDIEM
→ csDIEM share price ticks up; holders compound in DIEM, not USDC
USDC revenue lands directly on the RevenueSplitter contract. Anyone can trigger distribute() once the balance exceeds the minimum floor and the 23h cooldown has elapsed. The splitter is the only authorized operator for sDIEM.notifyRewardAmount(). csDIEM consumes from sDIEM downstream and never calls notifyRewardAmount() itself.
All deposited DIEM is immediately forward-staked on Venice (the DIEM token contract has staking built in). No liquid buffer is held.
claimFromVenice() and redeployExcess() callable by anyone.requestWithdraw() auto-initiates Venice unstake. After 24h, completeWithdraw() auto-claims from Venice. Users can cancelWithdraw() at any time.completeWithdraw() supports partial payouts when only some Venice-unstaked DIEM is available, preventing one user's unfunded batch from blocking others. After partial completion, Venice unstake is auto-initiated for remaining amounts.totalPendingNotInitiated. When the cooldown matures and a user completes, the next batch is auto-initiated. Worst-case withdrawal time: ~48h (two Venice cooldowns).csDIEM is a thin ERC-4626 vault layered on sDIEM. It does not interact with Venice directly — sDIEM handles that. The only mechanically novel piece is harvest():
harvest(uint256 deadline) — caller computes deadline at submission time. An internally-set deadline gives no mempool-delay protection (Pashov audit #1).exactInputSingle, with amountOutMin derived from a 1h TWAP and a max-slippage parameter (default 0.5%).minDiemPerUsdc must be set before any harvest can run (Pashov audit #3); admin can tune via setMinDiemPerUsdc.requestRedeem(shares) burns shares, records owed DIEM, optionally initiates an sDIEM withdrawal. After 24h, completeRedeem() pays out (with partial-fill support). cancelRedeem() re-mints at current rate (anti-arbitrage).contracts/
src/
sDIEM.sol Stake DIEM, earn USDC (Synthetix model)
sDIEMv2.sol v2: same model, ERC-20 + EIP-2612 transferable
RevenueSplitter.sol 20/80 USDC splitter: Safe + sDIEM
csDIEM.sol ERC-4626 auto-compounding wrapper over sDIEM
csDIEMv2.sol v2: canonical 4626 over sDIEM v2 (sync redeem)
DIEMVault.sol USDC deposit vault for relay credits
interfaces/
IsDIEM.sol sDIEM interface
IsDIEMv2.sol sDIEM v2 interface (IERC20 + IERC20Permit + IERC1271)
IRevenueSplitter.sol RevenueSplitter interface
IcsDIEM.sol csDIEM interface
IcsDIEMv2.sol csDIEM v2 interface (IERC4626)
IDIEMStaking.sol DIEM token staking interface (Base)
IDIEMVault.sol DIEMVault interface
ICLPool.sol Aerodrome Slipstream pool (TWAP oracle source)
ICLSwapRouter.sol Aerodrome Slipstream swap router
libraries/
OracleLibrary.sol TWAP price queries from CL pools
TickMath.sol sqrtPriceX96 ↔ tick conversion
FullMath.sol Uniswap-style mulDiv with 512-bit intermediates
test/
sDIEM.t.sol 67 unit/fuzz tests
sDIEMInvariant.t.sol 7 invariant tests
DIEMVault.t.sol 52 unit/fuzz tests
DIEMVaultInvariant.t.sol 3 invariant tests
RevenueSplitter.t.sol 20 unit/fuzz tests
RevenueSplitterInvariant.t.sol 2 invariant tests
RevenueSplitterFork.t.sol 1 Base-fork integration test
csDIEM.t.sol 56 unit/fuzz tests
csDIEMInvariant.t.sol 5 invariant tests
sDIEMv2.t.sol v2: ERC-20 + permit + checkpoint + queue semantics
sDIEMv2Invariant.t.sol v2: 8 invariants incl. transfer-preserves-earned
csDIEMv2.t.sol v2: standard 4626 + harvest + zap + pause-allows-redeem
csDIEMv2Invariant.t.sol v2: 8 invariants incl. monotonic share price
DiemV2Integration.t.sol v2: full DIEM → csDIEM → harvest → sDIEM → DIEM roundtrip
mocks/ MockDIEMStaking, MockSwapRouter, MockCLPool, MockERC20
script/
DeploySDiem.s.sol sDIEM deployment
DeployDIEMVault.s.sol DIEMVault deployment
DeployRevenueSplitter.s.sol RevenueSplitter deployment
DeployCSDiem.s.sol csDIEM deployment (hardened: pre/post asserts,
setMinDiemPerUsdc + transferAdmin in single broadcast)
DeploySDiemV2.s.sol sDIEM v2 deployment
DeployCSDiemV2.s.sol csDIEM v2 deployment (floor is constructor arg)
src/ Relay server (TypeScript / Bun / Hono)
index.ts Hono server: /v1/buy, /v1/chat/completions, etc.
deposit-watcher.ts Picks up DIEMVault Deposited events → SQLite
keeper-distribute.ts Daily cron — runs csDIEM.harvest() then RevenueSplitter.distribute()
admin.ts, borrower-cli.ts, ... Operator + user CLIs
scripts/
health-check.sh Daily Telegram alerter — flags missed cron, errored
runs (any "ERROR:" or "FATAL:" in latest run), and
mid-run kills (latest run never reached "done:")
app/ Staking UI (Next.js 16 / wagmi / RainbowKit / Tailwind 4)
Live at https://diem-relay.com
cd contracts
forge install
forge build
forge test # 269 tests across 13 suites (unit, fuzz, invariant, fork)
All contracts are deployed on Base (chain ID 8453).
| Contract | Address |
|---|---|
| DIEMVault | 0xdc9625b026f6Dd17F9d96e608592A9C592e27eEF |
| sDIEM | 0xdbF05AF4fdAA518AC9c4dc5aA49399b8dd0B4be2 |
| RevenueSplitter v3 | 0x213c8d7434E2ae7AA1C392767c5120778D413215 |
| csDIEM | 0x4899f5fBA1bf43C8Bea483bE6342e55Bc16e045a |
| sDIEM (superseded) | 0x59650b79eF4c2eC193B49DbFc23d50d48EBf9f34 |
| sDIEM (superseded) | 0x9566a919c7A4a7b22243736f39781A2787ddC11e |
All contracts are admin'd by the same 2/2 Safe 0x01Ea790410D9863A57771D992D2A72ea326DD7C9.
Deploy scripts:
cd contracts
# sDIEM
OPERATOR=0x... forge script script/DeploySDiem.s.sol \
--rpc-url $BASE_RPC_URL --broadcast --verify
# DIEMVault
forge script script/DeployDIEMVault.s.sol \
--rpc-url $BASE_RPC_URL --broadcast --verify
# RevenueSplitter (addresses default to Base mainnet + 2/2 Safe)
forge script script/DeployRevenueSplitter.s.sol \
--rpc-url $BASE_RPC_URL --broadcast --verify
# csDIEM (sets the mandatory minDiemPerUsdc floor and transfers admin
# to the Safe in the same broadcast — Safe must follow up with acceptAdmin)
SDIEM=0xdbF05... SWAP_ROUTER=0x... ORACLE_POOL=0x... TICK_SPACING=100 \
ADMIN=0x01Ea7904... MIN_DIEM_PER_USDC=<floor in DIEM-base-units-per-USDC> \
forge script script/DeployCSDiem.s.sol \
--rpc-url $BASE_RPC_URL --broadcast --verify
After RevenueSplitter deployment, the sDIEM admin must call sDIEM.setOperator(splitter) so the splitter becomes the sole caller of notifyRewardAmount. After csDIEM deployment, the Safe must call acceptAdmin() on the csDIEM contract to complete the two-step admin transfer.
A daily cron on the project's NUC runs src/keeper-distribute.ts at 00:05 UTC, which:
csDIEM.harvest(deadline) — claim previous 24h's USDC stream from sDIEM, swap via Slipstream CL, restake. Skipped silently if pendingHarvest < minHarvest.RevenueSplitter.distribute() — split the next 24h batch from RevenueSplitter v3 20/80 into platform Safe + sDIEM v2 rewards. Skipped silently if balance below minAmount or cooldown not elapsed.Each step has independent skip conditions and try/catch isolation — a swap-side failure on harvest does NOT block the platform-fee distribute. A second cron at 06:00 UTC runs scripts/health-check.sh, which alerts via Telegram on missed runs (>36h log staleness), errored runs (any ERROR:/FATAL: in the latest run), or mid-run kills (latest run never reached done:).
Access control: Two-step admin transfer on sDIEM, RevenueSplitter, and csDIEM. Separate operator role on sDIEM for reward notification.
Emergency pause: Deposits, staking, and harvest are gated behind pause. Withdrawals/redemptions and reward claims always allowed, even when paused — users can always exit.
Reentrancy: ReentrancyGuard on all mutative functions across all contracts. CEI (Checks-Effects-Interactions) pattern throughout.
Token safety: SafeERC20 for all ERC-20 operations. Zero-address checks on all constructors and admin setters.
Token recovery: recoverERC20() on all contracts for accidentally sent tokens, with safeguards preventing recovery of core assets (DIEM, USDC).
Venice cooldown handling: Claim-first semantics in initiateVeniceUnstake() — claims matured cooldown before initiating new one, preventing cooldown reset DoS (Bretzel finding M-01).
Venice unstake auto-initiation: completeWithdraw() calls _tryInitiateVeniceUnstake() before the payout check, ensuring deferred Venice unstakes are kicked off even when requestWithdraw() couldn't initiate them (Bretzel M-02 fix).
Partial withdrawal support: completeWithdraw() pays out available liquid DIEM rather than reverting when full amount isn't funded. Auto-initiates next Venice unstake batch after partial completion.
csDIEM swap protection: Caller-supplied harvest deadline (Pashov #1), mandatory absolute price floor minDiemPerUsdc (Pashov #3), uint128 bounds check on TWAP query (Pashov #4), 30-minute minimum TWAP window, max-slippage cap of 10%.
Reward dust: notifyRewardAmount() returns integer division rounding dust to caller instead of stranding it in the contract (Bretzel L-01).
| Audit | Scope | Result |
|---|---|---|
| Bretzel (March 2026) | sDIEM, DIEMVault | 0 Critical, 0 High, 1 Medium, 1 Low, 4 Informational. All findings remediated. |
| Pashov AI deep pass (March 2026) | sDIEM, DIEMVault | 2 additional findings, both remediated. |
| Internal Pashov (April 2026) | RevenueSplitter | Reviewed with same Pashov AI tooling, pending external pass. |
| Internal Pashov (April 2026) | csDIEM | 4 findings (1 high, 1 medium, 1 low, 1 below-threshold). Findings #1, #3, #4 applied. Finding #2 (timer-reset grief on syncWithdrawals) accepted as bounded by the existing if (sdiemPending > 0) return; guard. |
See contracts/AUDIT.md and contracts/KNOWN_ISSUES.md.
269 tests across 13 suites: unit, fuzz, invariant, and Base-fork integration tests. Key invariants verified:
totalStaked (sDIEM)totalDeposits (DIEMVault)totalAssets accounts for all DIEM (sdiemBalance + sdiemPending + liquid − pendingRedemptions)rewardPerToken, totalPendingNotInitiated ≤ totalPendingWithdrawals, transfer preserves earned(from) + earned(to) (the Synthetix-ERC20 trap), earned never underflowstotalAssets == sdiem.balanceOf(this), no shares without assets, monotonic share price, maxRedeem == balanceOf (4626 composability), maxWithdraw == previewRedeem(balanceOf), convertToAssets ∘ convertToShares ≈ identity, pause does not block redemption, recovery blacklist enforced