From 76143a8fe3b8e8de976f90752b6a9f6f038a7abc Mon Sep 17 00:00:00 2001 From: defiQUG Date: Sun, 10 May 2026 12:56:30 -0700 Subject: [PATCH] feat(token-aggregation): reports, PMM quotes, config; Engine X flash vaults - Expand token-aggregation API (report routes), canonical tokens, pools - Add flash vault contracts + tests (indexed, DODO cwUSDC, XAUT borrow) - PMM pools JSON, deploy/export scripts, metamask verified list Co-authored-by: Cursor --- config/chain138-pmm-pools.json | 11 +- .../flash/DBISEngineXFlashProofBorrower.sol | 87 + .../DBISEngineXIndexedLiquidityVault.sol | 242 ++ .../DBISEngineXSingleSidedDodoCwusdcVault.sol | 234 ++ .../flash/DBISEngineXVirtualBatchVault.sol | 187 +- .../flash/DBISEngineXXautUsdcBorrowVault.sol | 344 +++ .../MULTI_CHAIN_DEPLOYMENT_GUIDE.md | 4 +- .../REMAINING_TASKS_COMPLETE_LIST.md | 2 +- metamask/verified-contracts.json | 18 +- scripts/deployment/deploy-dapp-lxc.sh | 16 +- .../export-cronos-verification-sources.sh | 4 + services/token-aggregation/.env.example | 4 +- .../config/live-uniswap-v2-pool-catalog.json | 468 ++++ .../config/supply-proof-catalog.json | 2113 +++++++++++++++++ services/token-aggregation/deploy-to-vmid.sh | 4 +- services/token-aggregation/package-lock.json | 16 +- services/token-aggregation/package.json | 4 +- .../public/token-logos/gru/AVAX.svg | 6 + .../public/token-logos/gru/BNB.svg | 6 + .../public/token-logos/gru/CELO.svg | 7 + .../public/token-logos/gru/CRO.svg | 6 + .../public/token-logos/gru/ETH.svg | 6 + .../public/token-logos/gru/LINK.svg | 6 + .../public/token-logos/gru/POL.svg | 6 + .../public/token-logos/gru/WEMIX.svg | 6 + .../public/token-logos/gru/XDAI.svg | 6 + .../public/token-logos/gru/cAUDC.svg | 23 + .../public/token-logos/gru/cCADC.svg | 23 + .../public/token-logos/gru/cCHFC.svg | 23 + .../public/token-logos/gru/cEURC.svg | 23 + .../public/token-logos/gru/cEURT.svg | 23 + .../public/token-logos/gru/cGBPC.svg | 23 + .../public/token-logos/gru/cGBPT.svg | 23 + .../public/token-logos/gru/cJPYC.svg | 23 + .../public/token-logos/gru/cUSDC.svg | 23 + .../public/token-logos/gru/cUSDT.svg | 23 + .../public/token-logos/gru/cXAUC.svg | 23 + .../public/token-logos/gru/cXAUT.svg | 23 + .../public/token-logos/gru/chain-138.svg | 6 + ...16PY241zNtePyeK7ep1uf1RcARV2ynGAuRU8U7sSqS | Bin 0 -> 92252 bytes ...nJ6WyhYBCsYJ6NfS1BPAqiGKkCEuMxiC8ye93Co1hF | Bin 0 -> 92252 bytes ...FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong | Bin 0 -> 58973 bytes ...JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K | Bin 0 -> 92252 bytes .../token-logos/trustwallet/btc-logo.png | Bin 0 -> 4918 bytes .../generate-live-uniswap-v2-pool-catalog.ts | 163 ++ .../scripts/generate-supply-proof-catalog.ts | 238 ++ .../src/api/routes/bridge.ts | 39 +- .../src/api/routes/config.test.ts | 79 + .../src/api/routes/config.ts | 130 +- .../src/api/routes/report.test.ts | 210 ++ .../src/api/routes/report.ts | 1074 ++++++++- services/token-aggregation/src/api/server.ts | 78 +- .../src/config/canonical-tokens.test.ts | 35 + .../src/config/canonical-tokens.ts | 196 +- .../token-aggregation/src/config/chains.ts | 2 +- .../src/config/deployment-status.ts | 3 + .../src/config/gru-v2-deployment-pools.ts | 12 + .../token-aggregation/src/config/networks.ts | 11 +- .../token-aggregation/src/database/client.ts | 1 + .../database/repositories/market-data-repo.ts | 17 +- .../src/database/repositories/pool-repo.ts | 17 +- .../src/database/repositories/token-repo.ts | 14 +- .../src/services/pmm-onchain-quote.ts | 20 + .../DBISEngineXIndexedLiquidityVault.t.sol | 137 ++ ...BISEngineXSingleSidedDodoCwusdcVault.t.sol | 179 ++ test/flash/DBISEngineXVirtualBatchVault.t.sol | 183 +- .../DBISEngineXXautUsdcBorrowVault.t.sol | 175 ++ 67 files changed, 6972 insertions(+), 136 deletions(-) create mode 100644 contracts/flash/DBISEngineXFlashProofBorrower.sol create mode 100644 contracts/flash/DBISEngineXIndexedLiquidityVault.sol create mode 100644 contracts/flash/DBISEngineXSingleSidedDodoCwusdcVault.sol create mode 100644 contracts/flash/DBISEngineXXautUsdcBorrowVault.sol create mode 100644 services/token-aggregation/config/live-uniswap-v2-pool-catalog.json create mode 100644 services/token-aggregation/config/supply-proof-catalog.json create mode 100644 services/token-aggregation/public/token-logos/gru/AVAX.svg create mode 100644 services/token-aggregation/public/token-logos/gru/BNB.svg create mode 100644 services/token-aggregation/public/token-logos/gru/CELO.svg create mode 100644 services/token-aggregation/public/token-logos/gru/CRO.svg create mode 100644 services/token-aggregation/public/token-logos/gru/ETH.svg create mode 100644 services/token-aggregation/public/token-logos/gru/LINK.svg create mode 100644 services/token-aggregation/public/token-logos/gru/POL.svg create mode 100644 services/token-aggregation/public/token-logos/gru/WEMIX.svg create mode 100644 services/token-aggregation/public/token-logos/gru/XDAI.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cAUDC.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cCADC.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cCHFC.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cEURC.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cEURT.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cGBPC.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cGBPT.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cJPYC.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cUSDC.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cUSDT.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cXAUC.svg create mode 100644 services/token-aggregation/public/token-logos/gru/cXAUT.svg create mode 100644 services/token-aggregation/public/token-logos/gru/chain-138.svg create mode 100644 services/token-aggregation/public/token-logos/ipfs/QmPh16PY241zNtePyeK7ep1uf1RcARV2ynGAuRU8U7sSqS create mode 100644 services/token-aggregation/public/token-logos/ipfs/QmT2nJ6WyhYBCsYJ6NfS1BPAqiGKkCEuMxiC8ye93Co1hF create mode 100644 services/token-aggregation/public/token-logos/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong create mode 100644 services/token-aggregation/public/token-logos/ipfs/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K create mode 100644 services/token-aggregation/public/token-logos/trustwallet/btc-logo.png create mode 100644 services/token-aggregation/scripts/generate-live-uniswap-v2-pool-catalog.ts create mode 100644 services/token-aggregation/scripts/generate-supply-proof-catalog.ts create mode 100644 test/flash/DBISEngineXIndexedLiquidityVault.t.sol create mode 100644 test/flash/DBISEngineXSingleSidedDodoCwusdcVault.t.sol create mode 100644 test/flash/DBISEngineXXautUsdcBorrowVault.t.sol diff --git a/config/chain138-pmm-pools.json b/config/chain138-pmm-pools.json index 243a869..d646ffa 100644 --- a/config/chain138-pmm-pools.json +++ b/config/chain138-pmm-pools.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Desired-state pool spec for Chain 138 DODO PMM. Scripts should create and register only missing pools from this file, not redeploy contracts.", "version": "1.1.0", - "updated": "2026-04-19", + "updated": "2026-05-09", "chainId": 138, "defaults": { "lpFeeRate": 3, @@ -14,6 +14,10 @@ "cBTC": "0xe94260c555aC1d9D3CC9E1632883452ebDf0082E", "cUSDT": "0x93E66202A11B1772E55407B32B44e5Cd8eda7f22", "cUSDC": "0xf22258f57794CC8E06237084b353Ab30fFfa640b", + "cUSDT_V2": "0x9FBfab33882Efe0038DAa608185718b772EE5660", + "cUSDC_V2": "0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d", + "cUSDW": "0xca6BfA614935F1aB71c9aB106baa6fbB6057095E", + "cAUSDT": "0x5fdDF65733e3d590463F68f93Cf16E8c04081271", "cEURC": "0x8085961F9cF02b4d800A3c6d386D31da4B34266a", "cEURT": "0xdf4b71c61E5912712C1Bdd451416B9aC26949d72", "cGBPC": "0x003960f16D9d34F2e98d62723B6721Fb92074aD2", @@ -32,6 +36,7 @@ "cStarSymbols": [ "cUSDT", "cUSDC", + "cAUSDT", "cEURC", "cEURT", "cGBPC", @@ -60,8 +65,12 @@ { "baseSymbol": "cBTC", "quoteSymbol": "cUSDC" }, { "baseSymbol": "cBTC", "quoteSymbol": "cXAUC" }, { "baseSymbol": "cUSDT", "quoteSymbol": "cUSDC" }, + { "baseSymbol": "cUSDC_V2", "quoteSymbol": "cUSDT_V2" }, + { "baseSymbol": "cUSDW", "quoteSymbol": "cUSDC" }, { "baseSymbol": "cUSDT", "quoteSymbol": "USDT" }, { "baseSymbol": "cUSDC", "quoteSymbol": "USDC" }, + { "baseSymbol": "cAUSDT", "quoteSymbol": "cUSDC" }, + { "baseSymbol": "cAUSDT", "quoteSymbol": "cUSDT" }, { "baseSymbol": "cEURC", "quoteSymbol": "cUSDC" }, { "baseSymbol": "cEURT", "quoteSymbol": "cUSDC" }, { "baseSymbol": "cGBPC", "quoteSymbol": "cUSDC" }, diff --git a/contracts/flash/DBISEngineXFlashProofBorrower.sol b/contracts/flash/DBISEngineXFlashProofBorrower.sol new file mode 100644 index 0000000..ad7f507 --- /dev/null +++ b/contracts/flash/DBISEngineXFlashProofBorrower.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +/// @notice Minimal Engine X ERC-3156 borrower for proving same-transaction USDC working capital. +/// @dev Prefund this contract with at least the flash fee before calling `runFlashProof`. +contract DBISEngineXFlashProofBorrower is IERC3156FlashBorrower, Ownable { + using SafeERC20 for IERC20; + + bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + IERC3156FlashLender public immutable lender; + IERC20 public immutable usdc; + + mapping(bytes32 => bool) public usedProofIds; + + event EngineXFlashProof( + bytes32 indexed proofId, + address indexed initiator, + address indexed lender, + address token, + uint256 amount, + uint256 fee, + bytes32 iso20022DocumentHash, + bytes32 auditEnvelopeHash, + bytes32 pegProofHash + ); + + constructor(address lender_, address usdc_, address owner_) Ownable(owner_) { + require(lender_ != address(0) && usdc_ != address(0), "zero address"); + lender = IERC3156FlashLender(lender_); + usdc = IERC20(usdc_); + } + + function runFlashProof( + uint256 amount, + bytes32 proofId, + bytes32 iso20022DocumentHash, + bytes32 auditEnvelopeHash, + bytes32 pegProofHash + ) external onlyOwner returns (bool) { + require(proofId != bytes32(0), "zero proof"); + require(!usedProofIds[proofId], "proof used"); + require(iso20022DocumentHash != bytes32(0), "zero iso hash"); + require(auditEnvelopeHash != bytes32(0), "zero audit hash"); + require(pegProofHash != bytes32(0), "zero peg hash"); + + bytes memory data = abi.encode(msg.sender, proofId, iso20022DocumentHash, auditEnvelopeHash, pegProofHash); + return lender.flashLoan(this, address(usdc), amount, data); + } + + function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes calldata data) + external + override + returns (bytes32) + { + require(msg.sender == address(lender), "bad lender"); + require(initiator == address(this), "bad initiator"); + require(token == address(usdc), "bad token"); + + ( + address operator, + bytes32 proofId, + bytes32 iso20022DocumentHash, + bytes32 auditEnvelopeHash, + bytes32 pegProofHash + ) = abi.decode(data, (address, bytes32, bytes32, bytes32, bytes32)); + require(!usedProofIds[proofId], "proof used"); + usedProofIds[proofId] = true; + + usdc.forceApprove(msg.sender, amount + fee); + emit EngineXFlashProof( + proofId, operator, msg.sender, token, amount, fee, iso20022DocumentHash, auditEnvelopeHash, pegProofHash + ); + return _RETURN_VALUE; + } + + function withdraw(address token, address to, uint256 amount) external onlyOwner { + require(to != address(0), "zero to"); + IERC20(token).safeTransfer(to, amount); + } +} diff --git a/contracts/flash/DBISEngineXIndexedLiquidityVault.sol b/contracts/flash/DBISEngineXIndexedLiquidityVault.sol new file mode 100644 index 0000000..1618624 --- /dev/null +++ b/contracts/flash/DBISEngineXIndexedLiquidityVault.sol @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +interface IEngineXUniswapV3PoolLike { + function token0() external view returns (address); + function token1() external view returns (address); + function fee() external view returns (uint24); + function liquidity() external view returns (uint128); + + function slot0() + external + view + returns ( + uint160 sqrtPriceX96, + int24 tick, + uint16 observationIndex, + uint16 observationCardinality, + uint16 observationCardinalityNext, + uint8 feeProtocol, + bool unlocked + ); +} + +/// @notice Public indexed-liquidity proof anchor for Engine X. +/// @dev This contract does not claim virtual DEX volume. It anchors Engine X proof IDs to a public UniV3 pool state. +contract DBISEngineXIndexedLiquidityVault is Ownable { + address public immutable cWUSDC; + address public immutable usdc; + IEngineXUniswapV3PoolLike public immutable pool; + uint24 public immutable fee; + + uint256 public positionTokenId; + int24 public maxAbsTick; + uint128 public minLiquidity; + uint256 public minToken0Balance; + uint256 public minToken1Balance; + uint256 public maxProofSwapAmount; + bool public paused; + bool public operatorAllowlistEnabled; + + mapping(address => bool) public approvedOperator; + mapping(bytes32 => bool) public usedProofIds; + + struct IndexedProof { + bytes32 proofId; + bytes32 publicSwapTxHash; + bytes32 liquidityTxHash; + address outputRecipient; + uint256 exactOutputAmount; + bytes32 iso20022DocumentHash; + bytes32 auditEnvelopeHash; + bytes32 pegProofHash; + } + + event RiskControlsUpdated( + int24 maxAbsTick, + uint128 minLiquidity, + uint256 minToken0Balance, + uint256 minToken1Balance, + uint256 maxProofSwapAmount + ); + event PositionTokenIdUpdated(uint256 positionTokenId); + event Paused(address indexed operator); + event Unpaused(address indexed operator); + event OperatorAllowlistEnabledUpdated(bool enabled); + event OperatorApprovalUpdated(address indexed operator, bool approved); + event IndexedLiquidityProof( + bytes32 indexed proofId, + address indexed operator, + address indexed outputRecipient, + address pool, + uint24 fee, + uint256 positionTokenId, + uint160 sqrtPriceX96, + int24 tick, + uint128 liquidity, + uint256 token0Balance, + uint256 token1Balance, + uint256 exactOutputAmount, + bytes32 publicSwapTxHash, + bytes32 liquidityTxHash, + bytes32 iso20022DocumentHash, + bytes32 auditEnvelopeHash, + bytes32 pegProofHash + ); + + modifier whenNotPaused() { + require(!paused, "paused"); + _; + } + + modifier onlyApprovedOperator() { + require(!operatorAllowlistEnabled || approvedOperator[msg.sender], "operator not approved"); + _; + } + + constructor( + address cWUSDC_, + address usdc_, + address pool_, + address owner_, + int24 maxAbsTick_, + uint128 minLiquidity_, + uint256 maxProofSwapAmount_ + ) Ownable(owner_) { + require(cWUSDC_ != address(0) && usdc_ != address(0) && pool_ != address(0), "zero address"); + require(owner_ != address(0), "zero owner"); + cWUSDC = cWUSDC_; + usdc = usdc_; + pool = IEngineXUniswapV3PoolLike(pool_); + + address token0 = pool.token0(); + address token1 = pool.token1(); + require((token0 == cWUSDC_ && token1 == usdc_) || (token0 == usdc_ && token1 == cWUSDC_), "pool token mismatch"); + + fee = pool.fee(); + _setRiskControls(maxAbsTick_, minLiquidity_, 0, 0, maxProofSwapAmount_); + } + + function pause() external onlyOwner { + paused = true; + emit Paused(msg.sender); + } + + function unpause() external onlyOwner { + paused = false; + emit Unpaused(msg.sender); + } + + function setOperatorAllowlistEnabled(bool enabled) external onlyOwner { + operatorAllowlistEnabled = enabled; + emit OperatorAllowlistEnabledUpdated(enabled); + } + + function setOperatorApproved(address operator, bool approved) external onlyOwner { + require(operator != address(0), "zero operator"); + approvedOperator[operator] = approved; + emit OperatorApprovalUpdated(operator, approved); + } + + function setPositionTokenId(uint256 positionTokenId_) external onlyOwner { + positionTokenId = positionTokenId_; + emit PositionTokenIdUpdated(positionTokenId_); + } + + function setRiskControls( + int24 maxAbsTick_, + uint128 minLiquidity_, + uint256 minToken0Balance_, + uint256 minToken1Balance_, + uint256 maxProofSwapAmount_ + ) external onlyOwner { + _setRiskControls(maxAbsTick_, minLiquidity_, minToken0Balance_, minToken1Balance_, maxProofSwapAmount_); + } + + function currentPoolState() + public + view + returns ( + uint160 sqrtPriceX96, + int24 tick, + uint128 activeLiquidity, + uint256 token0Balance, + uint256 token1Balance + ) + { + (sqrtPriceX96, tick,,,,,) = pool.slot0(); + activeLiquidity = pool.liquidity(); + token0Balance = IERC20(pool.token0()).balanceOf(address(pool)); + token1Balance = IERC20(pool.token1()).balanceOf(address(pool)); + } + + function recordIndexedProof(IndexedProof calldata proof) + external + whenNotPaused + onlyApprovedOperator + returns (uint160 sqrtPriceX96, int24 tick, uint128 activeLiquidity) + { + require(proof.proofId != bytes32(0), "zero proof"); + require(!usedProofIds[proof.proofId], "proof used"); + require(proof.publicSwapTxHash != bytes32(0), "zero swap hash"); + require(proof.liquidityTxHash != bytes32(0), "zero liquidity hash"); + require(proof.outputRecipient != address(0), "zero recipient"); + require(proof.exactOutputAmount > 0, "zero output"); + require(maxProofSwapAmount == 0 || proof.exactOutputAmount <= maxProofSwapAmount, "proof amount too high"); + require(proof.iso20022DocumentHash != bytes32(0), "zero iso hash"); + require(proof.auditEnvelopeHash != bytes32(0), "zero audit hash"); + require(proof.pegProofHash != bytes32(0), "zero peg hash"); + + uint256 token0Balance; + uint256 token1Balance; + (sqrtPriceX96, tick, activeLiquidity, token0Balance, token1Balance) = currentPoolState(); + require(_absTick(tick) <= uint24(maxAbsTick), "tick drift too high"); + require(activeLiquidity >= minLiquidity, "insufficient liquidity"); + require(token0Balance >= minToken0Balance, "insufficient token0 balance"); + require(token1Balance >= minToken1Balance, "insufficient token1 balance"); + + usedProofIds[proof.proofId] = true; + emit IndexedLiquidityProof( + proof.proofId, + msg.sender, + proof.outputRecipient, + address(pool), + fee, + positionTokenId, + sqrtPriceX96, + tick, + activeLiquidity, + token0Balance, + token1Balance, + proof.exactOutputAmount, + proof.publicSwapTxHash, + proof.liquidityTxHash, + proof.iso20022DocumentHash, + proof.auditEnvelopeHash, + proof.pegProofHash + ); + } + + function _setRiskControls( + int24 maxAbsTick_, + uint128 minLiquidity_, + uint256 minToken0Balance_, + uint256 minToken1Balance_, + uint256 maxProofSwapAmount_ + ) internal { + require(maxAbsTick_ >= 0, "negative tick gate"); + maxAbsTick = maxAbsTick_; + minLiquidity = minLiquidity_; + minToken0Balance = minToken0Balance_; + minToken1Balance = minToken1Balance_; + maxProofSwapAmount = maxProofSwapAmount_; + emit RiskControlsUpdated(maxAbsTick_, minLiquidity_, minToken0Balance_, minToken1Balance_, maxProofSwapAmount_); + } + + function _absTick(int24 tick) internal pure returns (uint24) { + return tick >= 0 ? uint24(tick) : uint24(-tick); + } +} diff --git a/contracts/flash/DBISEngineXSingleSidedDodoCwusdcVault.sol b/contracts/flash/DBISEngineXSingleSidedDodoCwusdcVault.sol new file mode 100644 index 0000000..ede0fb0 --- /dev/null +++ b/contracts/flash/DBISEngineXSingleSidedDodoCwusdcVault.sol @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; + +interface IEngineXDodoPoolLike { + function _BASE_TOKEN_() external view returns (address); + function _QUOTE_TOKEN_() external view returns (address); + function querySellBase(address trader, uint256 payBaseAmount) + external + view + returns (uint256 receiveQuoteAmount, uint256 mtFee); + function querySellQuote(address trader, uint256 payQuoteAmount) + external + view + returns (uint256 receiveBaseAmount, uint256 mtFee); + function getVaultReserve() external view returns (uint256 baseReserve, uint256 quoteReserve); +} + +interface IEngineXDodoIntegrationLike { + function addLiquidity(address pool, uint256 baseAmount, uint256 quoteAmount) + external + returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare); +} + +/// @notice Engine X single-sided cWUSDC inventory wrapper for later DODO PMM promotion. +/// @dev cWUSDC-only inventory is accounting/support inventory, not executable public DODO liquidity. +/// DODO promotion is allowed only with nonzero base and quote amounts and passing canary guards. +contract DBISEngineXSingleSidedDodoCwusdcVault is Ownable, ReentrancyGuard { + using SafeERC20 for IERC20; + + IERC20 public immutable cWUSDC; + IERC20 public immutable quoteToken; + IEngineXDodoIntegrationLike public immutable dodoIntegration; + + address public dodoPool; + bool public paused; + + uint256 public accountedCwusdcInventory; + uint256 public accountedQuoteInventory; + uint256 public totalCwusdcPromotedToDodo; + uint256 public totalQuotePromotedToDodo; + + uint256 public sampleBaseIn; + uint256 public minQuoteOut; + uint256 public sampleQuoteIn; + uint256 public minBaseOut; + + event Paused(address indexed operator); + event Unpaused(address indexed operator); + event DodoPoolUpdated(address indexed pool); + event CanaryUpdated(uint256 sampleBaseIn, uint256 minQuoteOut, uint256 sampleQuoteIn, uint256 minBaseOut); + event CwusdcInventoryDeposited(address indexed from, uint256 amount); + event QuoteInventoryDeposited(address indexed from, uint256 amount); + event InventoryWithdrawn(address indexed token, address indexed to, uint256 amount); + event DodoLiquidityPromoted( + address indexed pool, + uint256 baseAmount, + uint256 quoteAmount, + uint256 baseShare, + uint256 quoteShare, + uint256 lpShare + ); + event UnaccountedTokenWithdrawn(address indexed token, address indexed to, uint256 amount); + + modifier whenNotPaused() { + require(!paused, "paused"); + _; + } + + constructor(address cWUSDC_, address quoteToken_, address dodoIntegration_, address owner_) Ownable(owner_) { + require(cWUSDC_ != address(0) && quoteToken_ != address(0), "zero token"); + require(dodoIntegration_ != address(0), "zero integration"); + require(owner_ != address(0), "zero owner"); + require(cWUSDC_ != quoteToken_, "same token"); + cWUSDC = IERC20(cWUSDC_); + quoteToken = IERC20(quoteToken_); + dodoIntegration = IEngineXDodoIntegrationLike(dodoIntegration_); + } + + function pause() external onlyOwner { + paused = true; + emit Paused(msg.sender); + } + + function unpause() external onlyOwner { + paused = false; + emit Unpaused(msg.sender); + } + + function setDodoPool(address pool) external onlyOwner { + _validatePool(pool); + dodoPool = pool; + emit DodoPoolUpdated(pool); + } + + function setCanary(uint256 sampleBaseIn_, uint256 minQuoteOut_, uint256 sampleQuoteIn_, uint256 minBaseOut_) + external + onlyOwner + { + require(sampleBaseIn_ > 0 || sampleQuoteIn_ > 0, "zero canary"); + require((sampleBaseIn_ == 0) == (minQuoteOut_ == 0), "base canary mismatch"); + require((sampleQuoteIn_ == 0) == (minBaseOut_ == 0), "quote canary mismatch"); + sampleBaseIn = sampleBaseIn_; + minQuoteOut = minQuoteOut_; + sampleQuoteIn = sampleQuoteIn_; + minBaseOut = minBaseOut_; + emit CanaryUpdated(sampleBaseIn_, minQuoteOut_, sampleQuoteIn_, minBaseOut_); + } + + function depositCwusdc(uint256 amount) external nonReentrant whenNotPaused { + require(amount > 0, "zero deposit"); + cWUSDC.safeTransferFrom(msg.sender, address(this), amount); + accountedCwusdcInventory += amount; + emit CwusdcInventoryDeposited(msg.sender, amount); + } + + function depositQuote(uint256 amount) external nonReentrant whenNotPaused { + require(amount > 0, "zero deposit"); + quoteToken.safeTransferFrom(msg.sender, address(this), amount); + accountedQuoteInventory += amount; + emit QuoteInventoryDeposited(msg.sender, amount); + } + + function withdrawCwusdcInventory(address to, uint256 amount) external onlyOwner nonReentrant { + require(to != address(0), "zero to"); + require(amount > 0, "zero withdraw"); + require(amount <= accountedCwusdcInventory, "insufficient cwusdc inventory"); + accountedCwusdcInventory -= amount; + cWUSDC.safeTransfer(to, amount); + _requireSolvent(); + emit InventoryWithdrawn(address(cWUSDC), to, amount); + } + + function withdrawQuoteInventory(address to, uint256 amount) external onlyOwner nonReentrant { + require(to != address(0), "zero to"); + require(amount > 0, "zero withdraw"); + require(amount <= accountedQuoteInventory, "insufficient quote inventory"); + accountedQuoteInventory -= amount; + quoteToken.safeTransfer(to, amount); + _requireSolvent(); + emit InventoryWithdrawn(address(quoteToken), to, amount); + } + + function promoteToDodo( + uint256 baseAmount, + uint256 quoteAmount, + uint256 minBaseShare, + uint256 minQuoteShare, + uint256 minLpShare + ) external onlyOwner nonReentrant whenNotPaused returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare) { + require(dodoPool != address(0), "pool not set"); + require(baseAmount > 0 && quoteAmount > 0, "two-sided required"); + require(baseAmount <= accountedCwusdcInventory, "insufficient cwusdc inventory"); + require(quoteAmount <= accountedQuoteInventory, "insufficient quote inventory"); + + accountedCwusdcInventory -= baseAmount; + accountedQuoteInventory -= quoteAmount; + + cWUSDC.forceApprove(address(dodoIntegration), baseAmount); + quoteToken.forceApprove(address(dodoIntegration), quoteAmount); + (baseShare, quoteShare, lpShare) = dodoIntegration.addLiquidity(dodoPool, baseAmount, quoteAmount); + cWUSDC.forceApprove(address(dodoIntegration), 0); + quoteToken.forceApprove(address(dodoIntegration), 0); + + require(baseShare >= minBaseShare, "base share too low"); + require(quoteShare >= minQuoteShare, "quote share too low"); + require(lpShare >= minLpShare, "lp share too low"); + require(canaryPasses(), "canary failed"); + + totalCwusdcPromotedToDodo += baseAmount; + totalQuotePromotedToDodo += quoteAmount; + _requireSolvent(); + emit DodoLiquidityPromoted(dodoPool, baseAmount, quoteAmount, baseShare, quoteShare, lpShare); + } + + function canaryPasses() public view returns (bool) { + if (dodoPool == address(0)) return false; + IEngineXDodoPoolLike pool = IEngineXDodoPoolLike(dodoPool); + (uint256 baseReserve, uint256 quoteReserve) = pool.getVaultReserve(); + if (baseReserve == 0 || quoteReserve == 0) return false; + if (sampleBaseIn > 0) { + (uint256 quoteOut,) = pool.querySellBase(address(this), sampleBaseIn); + if (quoteOut < minQuoteOut) return false; + } + if (sampleQuoteIn > 0) { + (uint256 baseOut,) = pool.querySellQuote(address(this), sampleQuoteIn); + if (baseOut < minBaseOut) return false; + } + return true; + } + + function solvencyState() + external + view + returns ( + uint256 cwusdcBalance, + uint256 quoteBalance, + uint256 cwusdcInventory, + uint256 quoteInventory, + bool solvent, + bool executable + ) + { + cwusdcBalance = cWUSDC.balanceOf(address(this)); + quoteBalance = quoteToken.balanceOf(address(this)); + cwusdcInventory = accountedCwusdcInventory; + quoteInventory = accountedQuoteInventory; + solvent = cwusdcBalance >= cwusdcInventory && quoteBalance >= quoteInventory; + executable = canaryPasses(); + } + + function rescueUnaccountedToken(address token, address to, uint256 amount) external onlyOwner nonReentrant { + require(to != address(0), "zero to"); + require(amount > 0, "zero withdraw"); + IERC20(token).safeTransfer(to, amount); + _requireSolvent(); + emit UnaccountedTokenWithdrawn(token, to, amount); + } + + function _validatePool(address pool) internal view { + require(pool != address(0), "zero pool"); + require(IEngineXDodoPoolLike(pool)._BASE_TOKEN_() == address(cWUSDC), "unexpected base"); + require(IEngineXDodoPoolLike(pool)._QUOTE_TOKEN_() == address(quoteToken), "unexpected quote"); + } + + function _requireSolvent() internal view { + require(cWUSDC.balanceOf(address(this)) >= accountedCwusdcInventory, "cwusdc insolvent"); + require(quoteToken.balanceOf(address(this)) >= accountedQuoteInventory, "quote insolvent"); + } +} diff --git a/contracts/flash/DBISEngineXVirtualBatchVault.sol b/contracts/flash/DBISEngineXVirtualBatchVault.sol index d9d2e20..8e8bb95 100644 --- a/contracts/flash/DBISEngineXVirtualBatchVault.sol +++ b/contracts/flash/DBISEngineXVirtualBatchVault.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; +import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; @@ -8,9 +10,12 @@ import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol /// @notice Engine X maintained proof vault with virtual batch settlement. /// @dev Use only for accounting proofs: it compresses identical maintained loops into one net settlement. -contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { +contract DBISEngineXVirtualBatchVault is IERC3156FlashLender, Ownable, ReentrancyGuard { using SafeERC20 for IERC20; + bytes32 private constant _FLASH_RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + uint256 public constant MAX_FLASH_FEE_BPS = 1_000; + IERC20 public immutable cWUSDC; IERC20 public immutable usdc; IERC20 public immutable xaut; @@ -22,7 +27,13 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { uint256 public totalVirtualLoops; uint256 public totalVirtualDebtUsdc; uint256 public totalVirtualCwusdcIn; + uint256 public totalFlashFeesCollectedUsdc; + uint256 public flashFeeBps = 5; + uint256 public maxFlashLoanAmount; + bool public paused; + bool public flashBorrowerAllowlistEnabled; mapping(bytes32 => bool) public usedProofIds; + mapping(address => bool) public approvedFlashBorrower; uint256 public immutable xautUsdPrice6; uint256 public immutable ltvBps; @@ -58,7 +69,27 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { bytes32 auditEnvelopeHash, bytes32 pegProofHash ); - event OwnerWithdraw(address indexed token, address indexed to, uint256 amount); + event PoolLiquidityWithdrawn(address indexed to, uint256 cwusdcAmount, uint256 usdcAmount); + event LenderUsdcWithdrawn(address indexed to, uint256 amount); + event UnaccountedTokenWithdrawn(address indexed token, address indexed to, uint256 amount); + event FlashFeeBpsUpdated(uint256 feeBps); + event MaxFlashLoanAmountUpdated(uint256 amount); + event Paused(address indexed operator); + event Unpaused(address indexed operator); + event FlashBorrowerAllowlistEnabledUpdated(bool enabled); + event FlashBorrowerApprovalUpdated(address indexed borrower, bool approved); + event EngineXFlashLoan( + address indexed initiator, + IERC3156FlashBorrower indexed receiver, + address indexed token, + uint256 amount, + uint256 fee + ); + + modifier whenNotPaused() { + require(!paused, "paused"); + _; + } constructor( address cWUSDC_, @@ -85,7 +116,7 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { maxRoundTripLossBps = maxRoundTripLossBps_; } - function seedPool(uint256 cwusdcAmount, uint256 usdcAmount) external onlyOwner nonReentrant { + function seedPool(uint256 cwusdcAmount, uint256 usdcAmount) external onlyOwner nonReentrant whenNotPaused { require(cwusdcAmount > 0 && usdcAmount > 0, "zero seed"); cWUSDC.safeTransferFrom(msg.sender, address(this), cwusdcAmount); usdc.safeTransferFrom(msg.sender, address(this), usdcAmount); @@ -94,7 +125,7 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { emit PoolSeeded(cwusdcAmount, usdcAmount); } - function fundLender(uint256 usdcAmount) external onlyOwner nonReentrant { + function fundLender(uint256 usdcAmount) external onlyOwner nonReentrant whenNotPaused { require(usdcAmount > 0, "zero fund"); usdc.safeTransferFrom(msg.sender, address(this), usdcAmount); lenderUsdcAvailable += usdcAmount; @@ -107,6 +138,38 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { emit SurplusReceiverUpdated(receiver); } + function pause() external onlyOwner { + paused = true; + emit Paused(msg.sender); + } + + function unpause() external onlyOwner { + paused = false; + emit Unpaused(msg.sender); + } + + function setFlashFeeBps(uint256 newFlashFeeBps) external onlyOwner { + require(newFlashFeeBps <= MAX_FLASH_FEE_BPS, "fee too high"); + flashFeeBps = newFlashFeeBps; + emit FlashFeeBpsUpdated(newFlashFeeBps); + } + + function setMaxFlashLoanAmount(uint256 amount) external onlyOwner { + maxFlashLoanAmount = amount; + emit MaxFlashLoanAmountUpdated(amount); + } + + function setFlashBorrowerAllowlistEnabled(bool enabled) external onlyOwner { + flashBorrowerAllowlistEnabled = enabled; + emit FlashBorrowerAllowlistEnabledUpdated(enabled); + } + + function setFlashBorrowerApproved(address borrower, bool approved) external onlyOwner { + require(borrower != address(0), "zero borrower"); + approvedFlashBorrower[borrower] = approved; + emit FlashBorrowerApprovalUpdated(borrower, approved); + } + function previewCwusdcInForExactUsdc(uint256 usdcOut) public view returns (uint256) { return _getAmountIn(usdcOut, poolCwusdcReserve, poolUsdcReserve); } @@ -119,6 +182,21 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { return poolCwusdcReserve > poolUsdcReserve ? poolCwusdcReserve - poolUsdcReserve : 0; } + function maxFlashLoan(address token) external view override returns (uint256) { + if (paused || token != address(usdc)) { + return 0; + } + if (maxFlashLoanAmount == 0 || maxFlashLoanAmount > lenderUsdcAvailable) { + return lenderUsdcAvailable; + } + return maxFlashLoanAmount; + } + + function flashFee(address token, uint256 amount) public view override returns (uint256) { + require(token == address(usdc), "unsupported flash token"); + return (amount * flashFeeBps) / 10_000; + } + function minimumXautCollateral(uint256 debtUsdc) public view returns (uint256) { uint256 numerator = debtUsdc * 1e6 * 10_000; uint256 denominator = xautUsdPrice6 * ltvBps; @@ -155,7 +233,11 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { totalNeutralizedCwusdcAmount = cwusdcLossPerLoop * virtualLoops; } - function runVirtualProof(bytes32 proofId, uint256 debtUsdcPerLoop, uint256 virtualLoops) external nonReentrant { + function runVirtualProof(bytes32 proofId, uint256 debtUsdcPerLoop, uint256 virtualLoops) + external + nonReentrant + whenNotPaused + { _runVirtualProofFor( msg.sender, proofId, debtUsdcPerLoop, virtualLoops, 0, msg.sender, bytes32(0), bytes32(0), bytes32(0) ); @@ -164,6 +246,7 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { function runVirtualProofTo(bytes32 proofId, uint256 debtUsdcPerLoop, uint256 virtualLoops, address outputRecipient) external nonReentrant + whenNotPaused { require(outputRecipient != address(0), "zero output"); _runVirtualProofFor( @@ -181,7 +264,7 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { bytes32 iso20022DocumentHash, bytes32 auditEnvelopeHash, bytes32 pegProofHash - ) external nonReentrant { + ) external nonReentrant whenNotPaused { require(outputRecipient != address(0), "zero output"); require(exactOutputAmount > 0, "zero exact output"); require(roundingReceiver != address(0), "zero rounding"); @@ -201,6 +284,48 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { ); } + function flashLoan(IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data) + external + override + nonReentrant + whenNotPaused + returns (bool) + { + require(token == address(usdc), "unsupported flash token"); + require(amount > 0, "zero flash amount"); + require(amount <= lenderUsdcAvailable, "insufficient lender usdc"); + require(maxFlashLoanAmount == 0 || amount <= maxFlashLoanAmount, "flash amount too high"); + require( + !flashBorrowerAllowlistEnabled || approvedFlashBorrower[address(receiver)], "flash borrower not approved" + ); + + uint256 fee = flashFee(token, amount); + uint256 balanceBefore = usdc.balanceOf(address(this)); + require(balanceBefore >= poolUsdcReserve + lenderUsdcAvailable, "accounting undercollateralized"); + + lenderUsdcAvailable -= amount; + usdc.safeTransfer(address(receiver), amount); + + bytes32 retval = receiver.onFlashLoan(msg.sender, token, amount, fee, data); + require(retval == _FLASH_RETURN_VALUE, "invalid flash callback"); + + uint256 expectedBalance = balanceBefore + fee; + uint256 balanceAfterCallback = usdc.balanceOf(address(this)); + if (balanceAfterCallback < expectedBalance) { + usdc.safeTransferFrom(address(receiver), address(this), expectedBalance - balanceAfterCallback); + } + require(usdc.balanceOf(address(this)) >= expectedBalance, "flash repayment failed"); + + lenderUsdcAvailable += amount + fee; + totalFlashFeesCollectedUsdc += fee; + require( + usdc.balanceOf(address(this)) >= poolUsdcReserve + lenderUsdcAvailable, "accounting undercollateralized" + ); + + emit EngineXFlashLoan(msg.sender, receiver, token, amount, fee); + return true; + } + function _runVirtualProofFor( address outputRecipient, bytes32 proofId, @@ -272,10 +397,58 @@ contract DBISEngineXVirtualBatchVault is Ownable, ReentrancyGuard { } } + function withdrawPoolLiquidity(address to, uint256 cwusdcAmount, uint256 usdcAmount) + external + onlyOwner + nonReentrant + { + require(to != address(0), "zero to"); + require(cwusdcAmount > 0 || usdcAmount > 0, "zero withdraw"); + require(cwusdcAmount <= poolCwusdcReserve, "insufficient pool cwusdc"); + require(usdcAmount <= poolUsdcReserve, "insufficient pool usdc"); + + uint256 nextCwusdcReserve = poolCwusdcReserve - cwusdcAmount; + uint256 nextUsdcReserve = poolUsdcReserve - usdcAmount; + require(nextCwusdcReserve == nextUsdcReserve, "would break maintained pool"); + + poolCwusdcReserve = nextCwusdcReserve; + poolUsdcReserve = nextUsdcReserve; + + if (cwusdcAmount > 0) { + cWUSDC.safeTransfer(to, cwusdcAmount); + } + if (usdcAmount > 0) { + usdc.safeTransfer(to, usdcAmount); + } + + emit PoolLiquidityWithdrawn(to, cwusdcAmount, usdcAmount); + } + + function withdrawLenderUsdc(address to, uint256 amount) external onlyOwner nonReentrant { + require(to != address(0), "zero to"); + require(amount > 0, "zero withdraw"); + require(amount <= lenderUsdcAvailable, "insufficient lender usdc"); + + lenderUsdcAvailable -= amount; + usdc.safeTransfer(to, amount); + + emit LenderUsdcWithdrawn(to, amount); + } + + /// @notice Rescue or migrate only tokens that are not backing Engine X pool/lender accounting. function withdraw(address token, address to, uint256 amount) external onlyOwner nonReentrant { require(to != address(0), "zero to"); + require(amount > 0, "zero withdraw"); IERC20(token).safeTransfer(to, amount); - emit OwnerWithdraw(token, to, amount); + _requireAccountingCollateralized(); + emit UnaccountedTokenWithdrawn(token, to, amount); + } + + function _requireAccountingCollateralized() internal view { + require(cWUSDC.balanceOf(address(this)) >= poolCwusdcReserve, "accounting undercollateralized"); + require( + usdc.balanceOf(address(this)) >= poolUsdcReserve + lenderUsdcAvailable, "accounting undercollateralized" + ); } function _getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256) { diff --git a/contracts/flash/DBISEngineXXautUsdcBorrowVault.sol b/contracts/flash/DBISEngineXXautUsdcBorrowVault.sol new file mode 100644 index 0000000..026b3b0 --- /dev/null +++ b/contracts/flash/DBISEngineXXautUsdcBorrowVault.sol @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; + +/// @notice Engine X XAUt-backed USDC borrowing vault. +/// @dev This vault lends only pre-funded USDC. cWUSDC can be referenced as proof +/// provenance, but debt is always repaid in official USDC. +contract DBISEngineXXautUsdcBorrowVault is Ownable, ReentrancyGuard { + using SafeERC20 for IERC20; + + uint256 public constant BPS = 10_000; + uint256 public constant MAX_LTV_BPS = 9_500; + uint256 public constant MAX_LIQUIDATION_THRESHOLD_BPS = 9_800; + uint256 public constant MAX_LIQUIDATION_BONUS_BPS = 2_000; + + IERC20 public immutable xaut; + IERC20 public immutable usdc; + IERC20 public immutable cWUSDC; + + uint256 public xautUsdPrice6; + uint256 public lastPriceUpdate; + bytes32 public lastPriceSourceHash; + + uint256 public ltvBps; + uint256 public liquidationThresholdBps; + uint256 public minHealthFactorBps; + uint256 public liquidationBonusBps; + uint256 public maxBorrowUsdc; + bool public paused; + + uint256 public lenderUsdcAvailable; + uint256 public totalCollateralXaut; + uint256 public totalDebtUsdc; + uint256 public totalCwusdcProofRepayUsdc; + + struct Position { + uint256 collateralXaut; + uint256 debtUsdc; + } + + mapping(address => Position) public positions; + + event PriceUpdated(uint256 price6, bytes32 indexed sourceHash); + event RiskParamsUpdated( + uint256 ltvBps, + uint256 liquidationThresholdBps, + uint256 minHealthFactorBps, + uint256 liquidationBonusBps, + uint256 maxBorrowUsdc + ); + event Paused(address indexed operator); + event Unpaused(address indexed operator); + event LenderFunded(address indexed funder, uint256 amount); + event LenderUsdcWithdrawn(address indexed to, uint256 amount); + event CollateralSupplied(address indexed account, uint256 amount); + event CollateralWithdrawn(address indexed account, address indexed to, uint256 amount); + event UsdcBorrowed(address indexed account, address indexed to, uint256 amount, uint256 debtAfter); + event UsdcRepaid(address indexed account, address indexed payer, uint256 amount, uint256 debtAfter); + event CwusdcSourcedRepay( + address indexed account, + address indexed payer, + uint256 amount, + bytes32 indexed publicSwapTxHash, + bytes32 iso20022DocumentHash, + bytes32 auditEnvelopeHash, + bytes32 pegProofHash + ); + event Liquidated( + address indexed account, + address indexed liquidator, + uint256 repayUsdc, + uint256 seizedXaut, + uint256 debtAfter + ); + event UnaccountedTokenWithdrawn(address indexed token, address indexed to, uint256 amount); + + modifier whenNotPaused() { + require(!paused, "paused"); + _; + } + + constructor( + address xaut_, + address usdc_, + address cWUSDC_, + address owner_, + uint256 xautUsdPrice6_, + uint256 ltvBps_, + uint256 liquidationThresholdBps_, + uint256 minHealthFactorBps_, + uint256 liquidationBonusBps_, + uint256 maxBorrowUsdc_, + bytes32 priceSourceHash_ + ) Ownable(owner_) { + require(xaut_ != address(0) && usdc_ != address(0) && cWUSDC_ != address(0), "zero token"); + require(owner_ != address(0), "zero owner"); + xaut = IERC20(xaut_); + usdc = IERC20(usdc_); + cWUSDC = IERC20(cWUSDC_); + _setPrice(xautUsdPrice6_, priceSourceHash_); + _setRiskParams( + ltvBps_, liquidationThresholdBps_, minHealthFactorBps_, liquidationBonusBps_, maxBorrowUsdc_ + ); + } + + function pause() external onlyOwner { + paused = true; + emit Paused(msg.sender); + } + + function unpause() external onlyOwner { + paused = false; + emit Unpaused(msg.sender); + } + + function setXautUsdPrice6(uint256 price6, bytes32 sourceHash) external onlyOwner { + _setPrice(price6, sourceHash); + } + + function setRiskParams( + uint256 ltvBps_, + uint256 liquidationThresholdBps_, + uint256 minHealthFactorBps_, + uint256 liquidationBonusBps_, + uint256 maxBorrowUsdc_ + ) external onlyOwner { + _setRiskParams( + ltvBps_, liquidationThresholdBps_, minHealthFactorBps_, liquidationBonusBps_, maxBorrowUsdc_ + ); + } + + function fundLender(uint256 amount) external nonReentrant whenNotPaused { + require(amount > 0, "zero fund"); + usdc.safeTransferFrom(msg.sender, address(this), amount); + lenderUsdcAvailable += amount; + emit LenderFunded(msg.sender, amount); + } + + function withdrawLenderUsdc(address to, uint256 amount) external onlyOwner nonReentrant { + require(to != address(0), "zero to"); + require(amount > 0, "zero withdraw"); + require(amount <= lenderUsdcAvailable, "insufficient lender usdc"); + lenderUsdcAvailable -= amount; + usdc.safeTransfer(to, amount); + emit LenderUsdcWithdrawn(to, amount); + } + + function supplyCollateral(uint256 amount) external nonReentrant whenNotPaused { + require(amount > 0, "zero collateral"); + xaut.safeTransferFrom(msg.sender, address(this), amount); + positions[msg.sender].collateralXaut += amount; + totalCollateralXaut += amount; + emit CollateralSupplied(msg.sender, amount); + } + + function withdrawCollateral(uint256 amount, address to) external nonReentrant whenNotPaused { + require(to != address(0), "zero to"); + require(amount > 0, "zero collateral"); + Position storage position = positions[msg.sender]; + require(amount <= position.collateralXaut, "insufficient collateral"); + position.collateralXaut -= amount; + totalCollateralXaut -= amount; + _requireHealthy(msg.sender); + xaut.safeTransfer(to, amount); + emit CollateralWithdrawn(msg.sender, to, amount); + } + + function borrowUsdc(uint256 amount, address to) external nonReentrant whenNotPaused { + require(to != address(0), "zero to"); + require(amount > 0, "zero borrow"); + require(amount <= lenderUsdcAvailable, "insufficient lender usdc"); + if (maxBorrowUsdc != 0) { + require(totalDebtUsdc + amount <= maxBorrowUsdc, "max borrow exceeded"); + } + + Position storage position = positions[msg.sender]; + position.debtUsdc += amount; + totalDebtUsdc += amount; + lenderUsdcAvailable -= amount; + _requireHealthy(msg.sender); + + usdc.safeTransfer(to, amount); + emit UsdcBorrowed(msg.sender, to, amount, position.debtUsdc); + } + + function repayUsdc(uint256 amount) external nonReentrant whenNotPaused returns (uint256 repaid) { + repaid = _repay(msg.sender, msg.sender, amount); + } + + function repayUsdcFor(address account, uint256 amount) external nonReentrant whenNotPaused returns (uint256 repaid) { + require(account != address(0), "zero account"); + repaid = _repay(account, msg.sender, amount); + } + + function repayUsdcFromCwusdcProof( + uint256 amount, + bytes32 publicSwapTxHash, + bytes32 iso20022DocumentHash, + bytes32 auditEnvelopeHash, + bytes32 pegProofHash + ) external nonReentrant whenNotPaused returns (uint256 repaid) { + require(publicSwapTxHash != bytes32(0), "zero swap hash"); + require(iso20022DocumentHash != bytes32(0), "zero iso hash"); + require(auditEnvelopeHash != bytes32(0), "zero audit hash"); + require(pegProofHash != bytes32(0), "zero peg hash"); + + repaid = _repay(msg.sender, msg.sender, amount); + totalCwusdcProofRepayUsdc += repaid; + emit CwusdcSourcedRepay( + msg.sender, msg.sender, repaid, publicSwapTxHash, iso20022DocumentHash, auditEnvelopeHash, pegProofHash + ); + } + + function liquidate(address account, uint256 repayAmount) external nonReentrant whenNotPaused returns (uint256 seized) { + require(account != address(0), "zero account"); + require(repayAmount > 0, "zero repay"); + require(healthFactorBps(account) < minHealthFactorBps, "position healthy"); + + Position storage position = positions[account]; + uint256 repaid = repayAmount > position.debtUsdc ? position.debtUsdc : repayAmount; + require(repaid > 0, "zero debt"); + seized = _xautForUsdcWithBonus(repaid); + require(seized <= position.collateralXaut, "insufficient collateral"); + + usdc.safeTransferFrom(msg.sender, address(this), repaid); + position.debtUsdc -= repaid; + totalDebtUsdc -= repaid; + lenderUsdcAvailable += repaid; + position.collateralXaut -= seized; + totalCollateralXaut -= seized; + xaut.safeTransfer(msg.sender, seized); + + emit Liquidated(account, msg.sender, repaid, seized, position.debtUsdc); + } + + function rescueUnaccountedToken(address token, address to, uint256 amount) external onlyOwner nonReentrant { + require(to != address(0), "zero to"); + require(amount > 0, "zero withdraw"); + IERC20(token).safeTransfer(to, amount); + _requireAccountingCollateralized(); + emit UnaccountedTokenWithdrawn(token, to, amount); + } + + function collateralValueUsd6(address account) public view returns (uint256) { + return collateralValueUsd6ForRaw(positions[account].collateralXaut); + } + + function collateralValueUsd6ForRaw(uint256 xautRaw) public view returns (uint256) { + return (xautRaw * xautUsdPrice6) / 1e6; + } + + function maxDebtForCollateral(uint256 xautRaw) public view returns (uint256) { + uint256 collateralUsd6 = collateralValueUsd6ForRaw(xautRaw); + uint256 byLtv = (collateralUsd6 * ltvBps) / BPS; + uint256 byHealth = (collateralUsd6 * liquidationThresholdBps) / minHealthFactorBps; + return byLtv < byHealth ? byLtv : byHealth; + } + + function maxAdditionalBorrow(address account) public view returns (uint256) { + uint256 maxDebt = maxDebtForCollateral(positions[account].collateralXaut); + if (positions[account].debtUsdc >= maxDebt) { + return 0; + } + return maxDebt - positions[account].debtUsdc; + } + + function healthFactorBps(address account) public view returns (uint256) { + Position memory position = positions[account]; + if (position.debtUsdc == 0) { + return type(uint256).max; + } + uint256 collateralUsd6 = collateralValueUsd6ForRaw(position.collateralXaut); + return (collateralUsd6 * liquidationThresholdBps) / position.debtUsdc; + } + + function _repay(address account, address payer, uint256 amount) internal returns (uint256 repaid) { + require(amount > 0, "zero repay"); + Position storage position = positions[account]; + require(position.debtUsdc > 0, "zero debt"); + repaid = amount > position.debtUsdc ? position.debtUsdc : amount; + usdc.safeTransferFrom(payer, address(this), repaid); + position.debtUsdc -= repaid; + totalDebtUsdc -= repaid; + lenderUsdcAvailable += repaid; + emit UsdcRepaid(account, payer, repaid, position.debtUsdc); + } + + function _requireHealthy(address account) internal view { + Position memory position = positions[account]; + if (position.debtUsdc == 0) { + return; + } + require(position.debtUsdc <= maxDebtForCollateral(position.collateralXaut), "exceeds collateral"); + require(healthFactorBps(account) >= minHealthFactorBps, "health too low"); + } + + function _xautForUsdcWithBonus(uint256 usdcAmount) internal view returns (uint256) { + uint256 numerator = usdcAmount * 1e6 * (BPS + liquidationBonusBps); + uint256 denominator = xautUsdPrice6 * BPS; + return (numerator + denominator - 1) / denominator; + } + + function _setPrice(uint256 price6, bytes32 sourceHash) internal { + require(price6 > 0, "zero price"); + require(sourceHash != bytes32(0), "zero source"); + xautUsdPrice6 = price6; + lastPriceUpdate = block.timestamp; + lastPriceSourceHash = sourceHash; + emit PriceUpdated(price6, sourceHash); + } + + function _setRiskParams( + uint256 ltvBps_, + uint256 liquidationThresholdBps_, + uint256 minHealthFactorBps_, + uint256 liquidationBonusBps_, + uint256 maxBorrowUsdc_ + ) internal { + require(ltvBps_ > 0 && ltvBps_ <= MAX_LTV_BPS, "bad ltv"); + require( + liquidationThresholdBps_ >= ltvBps_ && liquidationThresholdBps_ <= MAX_LIQUIDATION_THRESHOLD_BPS, + "bad threshold" + ); + require(minHealthFactorBps_ >= BPS, "bad health"); + require(liquidationBonusBps_ <= MAX_LIQUIDATION_BONUS_BPS, "bad bonus"); + ltvBps = ltvBps_; + liquidationThresholdBps = liquidationThresholdBps_; + minHealthFactorBps = minHealthFactorBps_; + liquidationBonusBps = liquidationBonusBps_; + maxBorrowUsdc = maxBorrowUsdc_; + emit RiskParamsUpdated( + ltvBps_, liquidationThresholdBps_, minHealthFactorBps_, liquidationBonusBps_, maxBorrowUsdc_ + ); + } + + function _requireAccountingCollateralized() internal view { + require(xaut.balanceOf(address(this)) >= totalCollateralXaut, "xaut undercollateralized"); + require(usdc.balanceOf(address(this)) >= lenderUsdcAvailable, "usdc undercollateralized"); + } +} diff --git a/docs/deployment/MULTI_CHAIN_DEPLOYMENT_GUIDE.md b/docs/deployment/MULTI_CHAIN_DEPLOYMENT_GUIDE.md index 569814d..795df11 100644 --- a/docs/deployment/MULTI_CHAIN_DEPLOYMENT_GUIDE.md +++ b/docs/deployment/MULTI_CHAIN_DEPLOYMENT_GUIDE.md @@ -1,7 +1,7 @@ # 🌐 Multi-Chain Deployment Guide - Complete Package **Version**: 1.0 -**Last Updated**: 2026-01-24 +**Last Updated**: 2026-05-09 **Status**: ✅ Foundation Complete - Ready for Expansion --- @@ -80,7 +80,7 @@ This guide covers the complete deployment of the Universal Cross-Chain Asset Hub - [ ] Hedera adapter + oracle service - [ ] Tron adapter + oracle service - [ ] TON adapter + oracle service -- [ ] Cosmos adapter (IBC integration) +- [ ] Cosmos adapter (IBC integration) — optional streams **A–E**: [COSMOS_ECOSYSTEM_CHAIN138_OPTIONAL_INTEGRATIONS_RUNBOOK.md](../../../docs/11-references/COSMOS_ECOSYSTEM_CHAIN138_OPTIONAL_INTEGRATIONS_RUNBOOK.md), [`config/cosmos-chain138-optional/README.md`](../../../config/cosmos-chain138-optional/README.md) - [ ] Solana adapter (Wormhole integration) ### **Phase 4: Hyperledger** ⚠️ diff --git a/docs/deployment/REMAINING_TASKS_COMPLETE_LIST.md b/docs/deployment/REMAINING_TASKS_COMPLETE_LIST.md index 621c2bf..df9e77c 100644 --- a/docs/deployment/REMAINING_TASKS_COMPLETE_LIST.md +++ b/docs/deployment/REMAINING_TASKS_COMPLETE_LIST.md @@ -83,7 +83,7 @@ - [ ] **BRG-DEP-002**: Deploy WETH10 bridge to ChainID 138 - 2-3h - [ ] **BRG-DEP-003**: Deploy LINK token to canonical address - 2-3h - [ ] **BRG-DEP-004**: Deploy remaining EVM adapters (Polygon, Arbitrum, Optimism, Base, Avalanche, BSC, Ethereum) - 10-15h -- [ ] **BRG-DEP-005**: Deploy remaining non-EVM adapters (Stellar, Algorand, Hedera, Tron, TON, Cosmos, Solana) - 20-30h +- [ ] **BRG-DEP-005**: Deploy remaining non-EVM adapters (Stellar, Algorand, Hedera, Tron, TON, Cosmos, Solana) - 20-30h — **Cosmos:** optional streams A–E (not production IBC today): [COSMOS_ECOSYSTEM_CHAIN138_OPTIONAL_INTEGRATIONS_RUNBOOK.md](../../../docs/11-references/COSMOS_ECOSYSTEM_CHAIN138_OPTIONAL_INTEGRATIONS_RUNBOOK.md), [`config/cosmos-chain138-optional/README.md`](../../../config/cosmos-chain138-optional/README.md) - [ ] **BRG-DEP-006**: Deploy Hyperledger components (Cacti, Fabric, Indy) - 15-20h --- diff --git a/metamask/verified-contracts.json b/metamask/verified-contracts.json index d2c7d75..a21b2ab 100644 --- a/metamask/verified-contracts.json +++ b/metamask/verified-contracts.json @@ -5,63 +5,63 @@ "name": "WETH", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/tokens/WETH.sol" }, { "name": "Multicall", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/utils/Multicall.sol" }, { "name": "CREATE2Factory", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/utils/CREATE2Factory.sol" }, { "name": "Aggregator", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/oracle/Aggregator.sol" }, { "name": "CCIPRouter", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/ccip/CCIPRouter.sol" }, { "name": "CCIPSender", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/ccip/CCIPSender.sol" }, { "name": "CCIPReceiver", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/ccip/CCIPReceiver.sol" }, { "name": "Voting", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/governance/Voting.sol" }, { "name": "MultiSig", "address": "0x0000000000000000000000000000000000000000", "verified": false, - "explorer": "https://explorer.d-bis.org/address/0x0000000000000000000000000000000000000000", + "explorer": "https://explorer.d-bis.org/addresses/0x0000000000000000000000000000000000000000", "source": "contracts/governance/MultiSig.sol" } ], diff --git a/scripts/deployment/deploy-dapp-lxc.sh b/scripts/deployment/deploy-dapp-lxc.sh index ab6ca76..3500117 100755 --- a/scripts/deployment/deploy-dapp-lxc.sh +++ b/scripts/deployment/deploy-dapp-lxc.sh @@ -3,10 +3,12 @@ # Usage: ./scripts/deployment/deploy-dapp-lxc.sh [--dry-run] [--skip-create] # --dry-run Print commands only. # --skip-create Use existing container 5801 (only install/build/serve). -# Env: PROXMOX_HOST (optional; if unset, run pct on current host), NODE (optional; pct --node), +# Env: PROXMOX_HOST (defaults from VMID via proxmox scripts/lib/load-project-env.sh get_host_for_vmid), +# NODE (optional; only with DEPLOY_PCT_ON_LOCAL_PVE=1 on a PVE node: pct --node), # VMID, HOSTNAME, IP_DAPP_LXC, TEMPLATE, STORAGE, NETWORK, MEMORY_MB, CORES, DISK_GB, # REPO_URL (git URL to clone) or REPO_PATH (local path to copy; no git in container), # ENV_FILE (path to .env for VITE_*). +# DEPLOY_PCT_ON_LOCAL_PVE=1 — only on a Proxmox hypervisor: run pct locally (no SSH). # See: docs/03-deployment/DAPP_LXC_DEPLOYMENT.md set -euo pipefail @@ -48,6 +50,16 @@ for a in "$@"; do [[ "$a" == "--skip-create" ]] && SKIP_CREATE=true done +PROXMOX_MONOREPO_ROOT="$(cd "$SMOM_ROOT/.." && pwd)" +if [[ -f "$PROXMOX_MONOREPO_ROOT/scripts/lib/require-proxmox-ssh-for-pct.sh" ]]; then + # shellcheck disable=SC1091 + source "$PROXMOX_MONOREPO_ROOT/scripts/lib/require-proxmox-ssh-for-pct.sh" + require_proxmox_ssh_for_pct || exit 1 +else + echo "ERROR: Missing $PROXMOX_MONOREPO_ROOT/scripts/lib/require-proxmox-ssh-for-pct.sh (run from proxmox monorepo checkout)." >&2 + exit 1 +fi + run_cmd() { if [[ -n "$PROXMOX_HOST" ]]; then ssh $SSH_OPTS root@"$PROXMOX_HOST" "$@" @@ -76,7 +88,7 @@ echo "" if ! $SKIP_CREATE; then if $DRY_RUN; then - echo "[DRY-RUN] Would create LXC $VMID on ${PROXMOX_HOST:-local} with hostname=$HOSTNAME, ip=$IP/24" + echo "[DRY-RUN] Would create LXC $VMID on ${PROXMOX_HOST:-this Proxmox node (local pct)} with hostname=$HOSTNAME, ip=$IP/24" exit 0 fi diff --git a/scripts/deployment/export-cronos-verification-sources.sh b/scripts/deployment/export-cronos-verification-sources.sh index 50a7ebd..f3aa0f6 100755 --- a/scripts/deployment/export-cronos-verification-sources.sh +++ b/scripts/deployment/export-cronos-verification-sources.sh @@ -7,6 +7,8 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" OUT_DIR="$PROJECT_ROOT/.cronos-verify" cd "$PROJECT_ROOT" +# Cronos mainnet requires Paris EVM bytecode (no PUSH0). Match `foundry.toml` profile `cronos_legacy`. +export FOUNDRY_PROFILE="${FOUNDRY_PROFILE:-cronos_legacy}" # Load .env via dotenv (RPC CR/LF trim). Fallback: raw source. if [[ -f "$SCRIPT_DIR/../lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 @@ -68,5 +70,7 @@ echo "Next: https://explorer.cronos.org/verifyContract" echo " 1. Select 'Solidity (Standard-Json-Input)'" echo " 2. Upload the *_standard_input.json file for each contract" echo " 3. See docs/deployment/CRONOS_VERIFICATION_RUNBOOK.md" +echo " 4. The verify form uses Google reCAPTCHA — Submit stays disabled until solved in the browser." +echo " 5. Compiler picker may list 0.8.21+ only; Foundry uses solc 0.8.20 by default — pick the version that matches deploy bytecode if verification fails." echo "" echo "Sources: $OUT_DIR/" diff --git a/services/token-aggregation/.env.example b/services/token-aggregation/.env.example index aa53b48..5c37376 100644 --- a/services/token-aggregation/.env.example +++ b/services/token-aggregation/.env.example @@ -26,8 +26,8 @@ CUSDC_ADDRESS_138=0xf22258f57794CC8E06237084b353Ab30fFfa640b # Compliant USD V2 (ERC-2612 / ERC-3009) — x402 / GRU transport. # Reference: docs/04-configuration/CHAIN138_X402_TOKEN_SUPPORT.md -CUSDT_V2_ADDRESS_138=0x8d342d321DdEe97D0c5011DAF8ca0B59DA617D29 -CUSDC_V2_ADDRESS_138=0x1ac3F4942a71E86A9682D91837E1E71b7BACdF99 +CUSDT_V2_ADDRESS_138=0x9FBfab33882Efe0038DAa608185718b772EE5660 +CUSDC_V2_ADDRESS_138=0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d # Live ALL Mainnet AUSDT compliant landing surface on Chain 138. CAUSDT_ADDRESS_138=0x5fdDF65733e3d590463F68f93Cf16E8c04081271 diff --git a/services/token-aggregation/config/live-uniswap-v2-pool-catalog.json b/services/token-aggregation/config/live-uniswap-v2-pool-catalog.json new file mode 100644 index 0000000..7716ea8 --- /dev/null +++ b/services/token-aggregation/config/live-uniswap-v2-pool-catalog.json @@ -0,0 +1,468 @@ +{ + "schema": "token-aggregation-live-uniswap-v2-pool-catalog/v1", + "generatedAt": "2026-05-09T05:43:40.305Z", + "sourceArtifacts": [ + "reports/extraction/promod-uniswap-v2-live-pair-discovery-latest.json", + "cross-chain-pmm-lps/config/deployment-status.json" + ], + "poolCount": 19, + "positiveLiquidityPoolCount": 19, + "pools": [ + { + "chainId": 1, + "chainName": "Ethereum Mainnet", + "poolAddress": "0x422608c5ddff909675ac2c5f872fd42f16b9287a", + "dex": "uniswap_v2", + "factoryAddress": "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f", + "routerAddress": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0xaf5017d0163ecb99d9b5d94e3b4d7b09af44d8ae", + "quoteAddress": "0x2de5f116bfce3d0f922d9c8351e0c5fc24b9284a", + "baseReserveRaw": "9900803423129", + "quoteReserveRaw": "9900803423131", + "baseReserveUnits": "9900803.423129", + "quoteReserveUnits": "9900803.423131", + "priceQuotePerBase": "1.000000000000202003808633131", + "deviationBps": "2.020038086331310000E-9", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 9900803.423129, + "reserve1Usd": 9900803.423131, + "totalLiquidityUsd": 19801606.84626 + }, + { + "chainId": 1, + "chainName": "Ethereum Mainnet", + "poolAddress": "0xc28706f899266b36bc43cc072b3a921bdf2c48d9", + "dex": "uniswap_v2", + "factoryAddress": "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f", + "routerAddress": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", + "baseSymbol": "cWUSDC", + "quoteSymbol": "USDC", + "baseAddress": "0x2de5f116bfce3d0f922d9c8351e0c5fc24b9284a", + "quoteAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "baseReserveRaw": "1267071063797", + "quoteReserveRaw": "2167762", + "baseReserveUnits": "1267071.063797", + "quoteReserveUnits": "2.167762", + "priceQuotePerBase": "0.000001710844846779092339761738687", + "deviationBps": "9999.982891551532209076602383", + "depthOk": false, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1267071.063797, + "reserve1Usd": 2.167762, + "totalLiquidityUsd": 1267073.2315590002 + }, + { + "chainId": 10, + "chainName": "Optimism", + "poolAddress": "0xe28bff306442a8a512d2441847c27211a7c4c613", + "dex": "uniswap_v2", + "factoryAddress": "0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf", + "routerAddress": "0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x04b2ae3c3bb3d70df506fad8717b0fbfc78ed7e6", + "quoteAddress": "0x377a5faa3162b3fc6f4e267301a3c817bad18105", + "baseReserveRaw": "3000000000", + "quoteReserveRaw": "3000000000", + "baseReserveUnits": "3000", + "quoteReserveUnits": "3000", + "priceQuotePerBase": "1", + "deviationBps": "0", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 3000, + "reserve1Usd": 3000, + "totalLiquidityUsd": 6000 + }, + { + "chainId": 25, + "chainName": "Cronos", + "poolAddress": "0x438d8e1a8e311d2ae4b75a38e0044675fd324133", + "dex": "uniswap_v2", + "factoryAddress": "0x3B44B2a187a7b3824131F8db5a74194D0a42Fc15", + "routerAddress": "0x145863Eb42Cf62847A6Ca784e6416C1682b1b2Ae", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x72948a7a813b60b37cd0c920c4657dbff54312b8", + "quoteAddress": "0x932566e5bb6bebf6b035b94f3de1f75f126304ec", + "baseReserveRaw": "3000000000", + "quoteReserveRaw": "3000000000", + "baseReserveUnits": "3000", + "quoteReserveUnits": "3000", + "priceQuotePerBase": "1", + "deviationBps": "0", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 3000, + "reserve1Usd": 3000, + "totalLiquidityUsd": 6000 + }, + { + "chainId": 56, + "chainName": "BSC (BNB Chain)", + "poolAddress": "0x639d7e64c6f1fc676226f20a0c42aecdd66545e8", + "dex": "uniswap_v2", + "factoryAddress": "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73", + "routerAddress": "0x10ED43C718714eb63d5aA57B78B54704E256024E", + "baseSymbol": "cWAUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0xe1a51bc037a79ab36767561b147eb41780124934", + "quoteAddress": "0x5355148c4740fcc3d7a96f05edd89ab14851206b", + "baseReserveRaw": "1500000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1500", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "0.6666666666666666666666666667", + "deviationBps": "3333.333333333333333333333333", + "depthOk": true, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1500, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2500 + }, + { + "chainId": 56, + "chainName": "BSC (BNB Chain)", + "poolAddress": "0x7e308c12bd609607df9c4137e30235d5a9da2a64", + "dex": "uniswap_v2", + "factoryAddress": "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73", + "routerAddress": "0x10ED43C718714eb63d5aA57B78B54704E256024E", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x9a1d0dbee997929ed02fd19e0e199704d20914db", + "quoteAddress": "0x5355148c4740fcc3d7a96f05edd89ab14851206b", + "baseReserveRaw": "3000000000", + "quoteReserveRaw": "3000000000", + "baseReserveUnits": "3000", + "quoteReserveUnits": "3000", + "priceQuotePerBase": "1", + "deviationBps": "0", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 3000, + "reserve1Usd": 3000, + "totalLiquidityUsd": 6000 + }, + { + "chainId": 56, + "chainName": "BSC (BNB Chain)", + "poolAddress": "0xe9b082baa73fa4dec7cb3cbd99b19d30bbfe1523", + "dex": "uniswap_v2", + "factoryAddress": "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73", + "routerAddress": "0x10ED43C718714eb63d5aA57B78B54704E256024E", + "baseSymbol": "cWAUSDT", + "quoteSymbol": "cWUSDT", + "baseAddress": "0xe1a51bc037a79ab36767561b147eb41780124934", + "quoteAddress": "0x9a1d0dbee997929ed02fd19e0e199704d20914db", + "baseReserveRaw": "1500000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1500", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "0.6666666666666666666666666667", + "deviationBps": "3333.333333333333333333333333", + "depthOk": true, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1500, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2500 + }, + { + "chainId": 100, + "chainName": "Gnosis Chain", + "poolAddress": "0x064d782be0113cb427f3af0de9335c9f34a1de34", + "dex": "uniswap_v2", + "factoryAddress": "0xc35DADB65012eC5796536bD9864eD8773aBc74C4", + "routerAddress": "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x0cb0192c056aa425c557bdead8e56c7eeabf7acf", + "quoteAddress": "0xd6969bc19b53f866c64f2148ae271b2dae0c58e4", + "baseReserveRaw": "4000000000", + "quoteReserveRaw": "4000000000", + "baseReserveUnits": "4000", + "quoteReserveUnits": "4000", + "priceQuotePerBase": "1", + "deviationBps": "0", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 4000, + "reserve1Usd": 4000, + "totalLiquidityUsd": 8000 + }, + { + "chainId": 137, + "chainName": "Polygon", + "poolAddress": "0x3411a20c39773d1a18cb53864893b236f41f1e99", + "dex": "uniswap_v2", + "factoryAddress": "0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32", + "routerAddress": "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x0cb0192c056aa425c557bdead8e56c7eeabf7acf", + "quoteAddress": "0xd6969bc19b53f866c64f2148ae271b2dae0c58e4", + "baseReserveRaw": "10994302668", + "quoteReserveRaw": "10996392462", + "baseReserveUnits": "10994.302668", + "quoteReserveUnits": "10996.392462", + "priceQuotePerBase": "1.000190079722480494476414209", + "deviationBps": "1.900797224804944764142090000", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 10994.302668, + "reserve1Usd": 10996.392462, + "totalLiquidityUsd": 21990.69513 + }, + { + "chainId": 137, + "chainName": "Polygon", + "poolAddress": "0x8cd2cb42b81f894eb10d15446db22a3b31d6fb2e", + "dex": "uniswap_v2", + "factoryAddress": "0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32", + "routerAddress": "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff", + "baseSymbol": "cWAUSDT", + "quoteSymbol": "cWUSDT", + "baseAddress": "0xf12e262f85107df26741726b074606cafa24aae7", + "quoteAddress": "0x0cb0192c056aa425c557bdead8e56c7eeabf7acf", + "baseReserveRaw": "1500000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1500", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "0.6666666666666666666666666667", + "deviationBps": "3333.333333333333333333333333", + "depthOk": true, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1500, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2500 + }, + { + "chainId": 137, + "chainName": "Polygon", + "poolAddress": "0xe6a5cb164d4af7e9794aed09ec373392d0e7216c", + "dex": "uniswap_v2", + "factoryAddress": "0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32", + "routerAddress": "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff", + "baseSymbol": "cWAUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0xf12e262f85107df26741726b074606cafa24aae7", + "quoteAddress": "0xd6969bc19b53f866c64f2148ae271b2dae0c58e4", + "baseReserveRaw": "1500000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1500", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "0.6666666666666666666666666667", + "deviationBps": "3333.333333333333333333333333", + "depthOk": true, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1500, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2500 + }, + { + "chainId": 8453, + "chainName": "Base", + "poolAddress": "0x56eb93f747d3b8251d43849cc72b39c1899fcaca", + "dex": "uniswap_v2", + "factoryAddress": "0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E", + "routerAddress": "0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x04b2ae3c3bb3d70df506fad8717b0fbfc78ed7e6", + "quoteAddress": "0x377a5faa3162b3fc6f4e267301a3c817bad18105", + "baseReserveRaw": "1000000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1000", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "1", + "deviationBps": "0", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 1000, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2000 + }, + { + "chainId": 42161, + "chainName": "Arbitrum One", + "poolAddress": "0x2b2ea2ea9e7617de09fcb5063befafa01a9ef2b4", + "dex": "uniswap_v2", + "factoryAddress": "0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E", + "routerAddress": "0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x73adaf7dba95221c080db5631466d2bc54f6a76b", + "quoteAddress": "0x0cb0192c056aa425c557bdead8e56c7eeabf7acf", + "baseReserveRaw": "3000000000", + "quoteReserveRaw": "3000000000", + "baseReserveUnits": "3000", + "quoteReserveUnits": "3000", + "priceQuotePerBase": "1", + "deviationBps": "0", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 3000, + "reserve1Usd": 3000, + "totalLiquidityUsd": 6000 + }, + { + "chainId": 42220, + "chainName": "Celo", + "poolAddress": "0x6f97de8ab68c722dcbc02cea0ce6b587b8210052", + "dex": "uniswap_v2", + "factoryAddress": "0x62d5b84bE28a183aBB507E125B384122D2C25fAE", + "routerAddress": "0xE3D8bd6Aed4F159bc8000a9cD47CffDb95F96121", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x73376eb92c16977b126db9112936a20fa0de3442", + "quoteAddress": "0x4c38f9a5ed68a04cd28a72e8c68c459ec34576f3", + "baseReserveRaw": "1000000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1000", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "1", + "deviationBps": "0", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 1000, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2000 + }, + { + "chainId": 42220, + "chainName": "Celo", + "poolAddress": "0xd3b55d6d7c08fdbf5f201e486992643cff410d91", + "dex": "uniswap_v2", + "factoryAddress": "0x62d5b84bE28a183aBB507E125B384122D2C25fAE", + "routerAddress": "0xE3D8bd6Aed4F159bc8000a9cD47CffDb95F96121", + "baseSymbol": "cWAUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0xc158b6cd3a3088c52f797d41f5aa02825361629e", + "quoteAddress": "0x4c38f9a5ed68a04cd28a72e8c68c459ec34576f3", + "baseReserveRaw": "1500000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1500", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "0.6666666666666666666666666667", + "deviationBps": "3333.333333333333333333333333", + "depthOk": true, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1500, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2500 + }, + { + "chainId": 42220, + "chainName": "Celo", + "poolAddress": "0xee9eebf89c1424e63efc888929e43a9423357d39", + "dex": "uniswap_v2", + "factoryAddress": "0x62d5b84bE28a183aBB507E125B384122D2C25fAE", + "routerAddress": "0xE3D8bd6Aed4F159bc8000a9cD47CffDb95F96121", + "baseSymbol": "cWAUSDT", + "quoteSymbol": "cWUSDT", + "baseAddress": "0xc158b6cd3a3088c52f797d41f5aa02825361629e", + "quoteAddress": "0x73376eb92c16977b126db9112936a20fa0de3442", + "baseReserveRaw": "1500000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1500", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "0.6666666666666666666666666667", + "deviationBps": "3333.333333333333333333333333", + "depthOk": true, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1500, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2500 + }, + { + "chainId": 43114, + "chainName": "Avalanche C-Chain", + "poolAddress": "0x418322f48d857277ec4bcc96bc1580accb7ea253", + "dex": "uniswap_v2", + "factoryAddress": "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10", + "routerAddress": "0x60aE616a2155Ee3d9A68541Ba4544862310933d4", + "baseSymbol": "cWAUSDT", + "quoteSymbol": "cWUSDT", + "baseAddress": "0xff3084410a732231472ee9f93f5855da89cc5254", + "quoteAddress": "0x8142ba530b08f3950128601f00daaa678213dfdf", + "baseReserveRaw": "1500000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1500", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "0.6666666666666666666666666667", + "deviationBps": "3333.333333333333333333333333", + "depthOk": true, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1500, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2500 + }, + { + "chainId": 43114, + "chainName": "Avalanche C-Chain", + "poolAddress": "0x79c8ea153e77bc69b989f59f69bfa44c466d5dee", + "dex": "uniswap_v2", + "factoryAddress": "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10", + "routerAddress": "0x60aE616a2155Ee3d9A68541Ba4544862310933d4", + "baseSymbol": "cWUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0x8142ba530b08f3950128601f00daaa678213dfdf", + "quoteAddress": "0x0c242b513008cd49c89078f5afb237a3112251eb", + "baseReserveRaw": "10000800000", + "quoteReserveRaw": "10000800000", + "baseReserveUnits": "10000.8", + "quoteReserveUnits": "10000.8", + "priceQuotePerBase": "1", + "deviationBps": "0", + "depthOk": true, + "parityOk": true, + "healthy": true, + "reserve0Usd": 10000.8, + "reserve1Usd": 10000.8, + "totalLiquidityUsd": 20001.6 + }, + { + "chainId": 43114, + "chainName": "Avalanche C-Chain", + "poolAddress": "0xaad6aed8d28b0195d19b4d17f8ee9a1837ff2dce", + "dex": "uniswap_v2", + "factoryAddress": "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10", + "routerAddress": "0x60aE616a2155Ee3d9A68541Ba4544862310933d4", + "baseSymbol": "cWAUSDT", + "quoteSymbol": "cWUSDC", + "baseAddress": "0xff3084410a732231472ee9f93f5855da89cc5254", + "quoteAddress": "0x0c242b513008cd49c89078f5afb237a3112251eb", + "baseReserveRaw": "1500000000", + "quoteReserveRaw": "1000000000", + "baseReserveUnits": "1500", + "quoteReserveUnits": "1000", + "priceQuotePerBase": "0.6666666666666666666666666667", + "deviationBps": "3333.333333333333333333333333", + "depthOk": true, + "parityOk": false, + "healthy": false, + "reserve0Usd": 1500, + "reserve1Usd": 1000, + "totalLiquidityUsd": 2500 + } + ] +} diff --git a/services/token-aggregation/config/supply-proof-catalog.json b/services/token-aggregation/config/supply-proof-catalog.json new file mode 100644 index 0000000..96861f3 --- /dev/null +++ b/services/token-aggregation/config/supply-proof-catalog.json @@ -0,0 +1,2113 @@ +{ + "schema": "token-aggregation-supply-proof-catalog/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "proofs": [ + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 1, + "name": "Ethereum Mainnet", + "referenceBlock": 25054993 + }, + "token": { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "decimals": 6, + "totalSupplyRaw": "55047993783402955", + "totalSupplyUnits": "55047993783.402955" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "55047993783.402955", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 1, + "name": "Ethereum Mainnet", + "referenceBlock": 25054993 + }, + "token": { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Tether USD", + "onchainSymbol": "USDT", + "decimals": 6, + "totalSupplyRaw": "97071875962553520", + "totalSupplyUnits": "97071875962.55352" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "97071875962.55352", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "mainnet-cwusdc-supply-proof/v1", + "generatedAt": "2026-05-08T03:16:54Z", + "network": { + "chainId": 1, + "name": "Ethereum Mainnet", + "referenceBlock": 25047586 + }, + "token": { + "address": "0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a", + "name": "Wrapped cUSDC", + "symbol": "cWUSDC", + "decimals": 6, + "verifiedSource": { + "etherscan": "https://etherscan.io/token/0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a", + "sourcifyFullMatch": true, + "compiler": "0.8.20+commit.a1b79de6" + }, + "totalSupplyRaw": "10451316981309788", + "totalSupplyUnits": "10451316981.309788" + }, + "knownBalances": { + "operator": { + "address": "0x4A666F96fC8764181194447A7dFdb7d471b301C8", + "balanceRaw": "56772617595692", + "balanceUnits": "56772617.595692" + }, + "engineXVirtualBatchVault": { + "address": "0xf108586d1FC330EA1D4EA4ff8fd983cde94279B1", + "balanceRaw": "0", + "balanceUnits": "0" + }, + "uniswapV3CwusdcUsdcPool": { + "address": "0x1Cf2e685682C7F7beF508F0Af15Dfb5CDda01ee3", + "balanceRaw": "183290270", + "balanceUnits": "183.290270" + }, + "uniswapV2CwusdcUsdcPair": { + "address": "0xC28706F899266b36BC43cc072b3a921BDf2C48D9", + "balanceRaw": "1266860669082", + "balanceUnits": "1266860.669082" + } + }, + "trackerSurfaces": { + "etherscan": { + "status": "verified_contract_page_live", + "url": "https://etherscan.io/token/0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a" + }, + "dexscreener": { + "status": "indexed", + "tokenUrl": "https://dexscreener.com/ethereum/0x2de5f116bfce3d0f922d9c8351e0c5fc24b9284a", + "pools": [ + "https://dexscreener.com/ethereum/0x1cf2e685682c7f7bef508f0af15dfb5cdda01ee3", + "https://dexscreener.com/ethereum/0xc28706f899266b36bc43cc072b3a921bdf2c48d9" + ] + }, + "geckoTerminal": { + "status": "indexed", + "pools": [ + { + "address": "0x1cf2e685682c7f7bef508f0af15dfb5cdda01ee3", + "url": "https://www.geckoterminal.com/eth/pools/0x1cf2e685682c7f7bef508f0af15dfb5cdda01ee3", + "reserveUsd": "179.1416", + "volume24hUsd": "90.6693898501" + }, + { + "address": "0xc28706f899266b36bc43cc072b3a921bdf2c48d9", + "url": "https://www.geckoterminal.com/eth/pools/0xc28706f899266b36bc43cc072b3a921bdf2c48d9", + "reserveUsd": "4.3241", + "volume24hUsd": "114770.233085417" + } + ] + }, + "coinMarketCapDex": { + "status": "token_page_reachable", + "url": "https://dex.coinmarketcap.com/token/ethereum/0x2de5f116bfce3d0f922d9c8351e0c5fc24b9284a/", + "note": "CMC DEX discoverability is not the same as full CoinMarketCap listing acceptance." + }, + "coinGecko": { + "status": "not_listed_by_contract_api", + "note": "CoinGecko Ethereum contract lookup returned 404 during the 2026-05-08 readiness pass." + } + }, + "circulatingSupplyMethodology": { + "status": "ready_for_tracker_review", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "10451316981.309788", + "notes": [ + "No public tracker has accepted a circulating-supply value for this contract yet.", + "If a tracker requires exclusion of operator, treasury, bridge, or protocol-controlled balances, use the knownBalances section plus any additional signed treasury inventory supplied at submission time.", + "The value above is an on-chain supply proof, not a third-party listing approval." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 1, + "name": "Ethereum Mainnet", + "referenceBlock": 25054993 + }, + "token": { + "address": "0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "136106860161405", + "totalSupplyUnits": "136106860.161405" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "136106860.161405", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 10, + "name": "Optimism", + "referenceBlock": 151350237 + }, + "token": { + "address": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "216872376232530", + "totalSupplyUnits": "216872376.23253" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "216872376.23253", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 10, + "name": "Optimism", + "referenceBlock": 151350239 + }, + "token": { + "address": "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Tether USD", + "onchainSymbol": "USDT", + "decimals": 6, + "totalSupplyRaw": "201850485038093", + "totalSupplyUnits": "201850485.038093" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "201850485.038093", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 10, + "name": "Optimism", + "referenceBlock": 151350241 + }, + "token": { + "address": "0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105", + "name": "USD Coin (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDC", + "onchainName": "Wrapped cUSDC", + "onchainSymbol": "cWUSDC", + "decimals": 6, + "totalSupplyRaw": "16001000000", + "totalSupplyUnits": "16001.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "16001.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 10, + "name": "Optimism", + "referenceBlock": 151350241 + }, + "token": { + "address": "0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "onchainName": "Wrapped cUSDT", + "onchainSymbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "16001000000", + "totalSupplyUnits": "16001.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "16001.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 25, + "name": "Cronos", + "referenceBlock": 70089434 + }, + "token": { + "address": "0xc21223249CA28397B4B6541dfFaEcC539BfF0c59", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "179445548315541", + "totalSupplyUnits": "179445548.315541" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "179445548.315541", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 25, + "name": "Cronos", + "referenceBlock": 70089340 + }, + "token": { + "address": "0x66e428c3f67a68878562e79A0234c1F83c208770", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Tether USD", + "onchainSymbol": "USDT", + "decimals": 6, + "totalSupplyRaw": "89024964111949", + "totalSupplyUnits": "89024964.111949" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "89024964.111949", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 56, + "name": "BSC (BNB Chain)", + "referenceBlock": 97212275 + }, + "token": { + "address": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin", + "onchainSymbol": "USDC", + "decimals": 18, + "totalSupplyRaw": "1288999879439803987446539541", + "totalSupplyUnits": "1288999879.439803987446539541" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "1288999879.439803987446539541", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 56, + "name": "BSC (BNB Chain)", + "referenceBlock": 97212284 + }, + "token": { + "address": "0x55d398326f99059fF775485246999027B3197955", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Tether USD", + "onchainSymbol": "USDT", + "decimals": 18, + "totalSupplyRaw": "9184992541113839747386612540", + "totalSupplyUnits": "9184992541.11383974738661254" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "9184992541.11383974738661254", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 56, + "name": "BSC (BNB Chain)", + "referenceBlock": 97212289 + }, + "token": { + "address": "0xe1a51Bc037a79AB36767561B147eb41780124934", + "name": "Alltra USD Token (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWAUSDT", + "onchainName": "Wrapped cAUSDT", + "onchainSymbol": "cWAUSDT", + "decimals": 6, + "totalSupplyRaw": "362506000000", + "totalSupplyUnits": "362506.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "362506.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 56, + "name": "BSC (BNB Chain)", + "referenceBlock": 97212291 + }, + "token": { + "address": "0x5355148C4740fcc3D7a96F05EdD89AB14851206b", + "name": "USD Coin (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDC", + "onchainName": "Wrapped cUSDC", + "onchainSymbol": "cWUSDC", + "decimals": 6, + "totalSupplyRaw": "1993283000000", + "totalSupplyUnits": "1993283.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "1993283.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 56, + "name": "BSC (BNB Chain)", + "referenceBlock": 97212294 + }, + "token": { + "address": "0x9a1D0dBEE997929ED02fD19E0E199704d20914dB", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "onchainName": "Wrapped cUSDT", + "onchainSymbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "1993283000000", + "totalSupplyUnits": "1993283.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "1993283.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 56, + "name": "BSC (BNB Chain)", + "referenceBlock": 97212298 + }, + "token": { + "address": "0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55", + "name": "USD W (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDW", + "onchainName": "Wrapped cUSDW", + "onchainSymbol": "cWUSDW", + "decimals": 6, + "totalSupplyRaw": "361506000000", + "totalSupplyUnits": "361506.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "361506.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 100, + "name": "Gnosis Chain", + "referenceBlock": 46080039 + }, + "token": { + "address": "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD//C on xDai", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "18374759200634", + "totalSupplyUnits": "18374759.200634" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "18374759.200634", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 100, + "name": "Gnosis Chain", + "referenceBlock": 46080039 + }, + "token": { + "address": "0x4ECaBa5870353805a9F068101A40E0f32ed605C6", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Tether USD on xDai", + "onchainSymbol": "USDT", + "decimals": 6, + "totalSupplyRaw": "1055804706651", + "totalSupplyUnits": "1055804.706651" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "1055804.706651", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 100, + "name": "Gnosis Chain", + "referenceBlock": 46080040 + }, + "token": { + "address": "0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4", + "name": "USD Coin (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDC", + "onchainName": "Wrapped cUSDC", + "onchainSymbol": "cWUSDC", + "decimals": 6, + "totalSupplyRaw": "15000000000", + "totalSupplyUnits": "15000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "15000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 100, + "name": "Gnosis Chain", + "referenceBlock": 46080041 + }, + "token": { + "address": "0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "onchainName": "Wrapped cUSDT", + "onchainSymbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "15000000000", + "totalSupplyUnits": "15000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "15000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 137, + "name": "Polygon", + "referenceBlock": 86605454 + }, + "token": { + "address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "695940174693096", + "totalSupplyUnits": "695940174.693096" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "695940174.693096", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 137, + "name": "Polygon", + "referenceBlock": 86605456 + }, + "token": { + "address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "USDT0", + "onchainSymbol": "USDT0", + "decimals": 6, + "totalSupplyRaw": "831909856146147", + "totalSupplyUnits": "831909856.146147" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "831909856.146147", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 137, + "name": "Polygon", + "referenceBlock": 86605457 + }, + "token": { + "address": "0xf12e262F85107df26741726b074606CaFa24AAe7", + "name": "Alltra USD Token (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWAUSDT", + "onchainName": "Wrapped cAUSDT", + "onchainSymbol": "cWAUSDT", + "decimals": 6, + "totalSupplyRaw": "3000000000", + "totalSupplyUnits": "3000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "3000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 137, + "name": "Polygon", + "referenceBlock": 86605458 + }, + "token": { + "address": "0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4", + "name": "USD Coin (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDC", + "onchainName": "Wrapped cUSDC", + "onchainSymbol": "cWUSDC", + "decimals": 6, + "totalSupplyRaw": "22000000000", + "totalSupplyUnits": "22000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "22000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 137, + "name": "Polygon", + "referenceBlock": 86605459 + }, + "token": { + "address": "0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "onchainName": "Wrapped cUSDT", + "onchainSymbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "21998313972", + "totalSupplyUnits": "21998.313972" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "21998.313972", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952095 + }, + "token": { + "address": "0xD51482e567c03899eecE3CAe8a058161FD56069D", + "name": "Australian Dollar (Compliant)", + "symbol": "cAUDC", + "onchainName": "Australian Dollar (Compliant)", + "onchainSymbol": "cAUDC", + "decimals": 6, + "totalSupplyRaw": "56804486580000", + "totalSupplyUnits": "56804486.58" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "56804486.58", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952086 + }, + "token": { + "address": "0x5fdDF65733e3d590463F68f93Cf16E8c04081271", + "name": "Alltra USD Token (Compliant)", + "symbol": "cAUSDT", + "onchainName": "Alltra USD Token (Compliant)", + "onchainSymbol": "cAUSDT", + "decimals": 6, + "totalSupplyRaw": "32707131000004", + "totalSupplyUnits": "32707131.000004" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "32707131.000004", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952095 + }, + "token": { + "address": "0x54dBd40cF05e15906A2C21f600937e96787f5679", + "name": "Canadian Dollar (Compliant)", + "symbol": "cCADC", + "onchainName": "Canadian Dollar (Compliant)", + "onchainSymbol": "cCADC", + "decimals": 6, + "totalSupplyRaw": "44871934240000", + "totalSupplyUnits": "44871934.24" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "44871934.24", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952095 + }, + "token": { + "address": "0x873990849DDa5117d7C644f0aF24370797C03885", + "name": "Swiss Franc (Compliant)", + "symbol": "cCHFC", + "onchainName": "Swiss Franc (Compliant)", + "onchainSymbol": "cCHFC", + "decimals": 6, + "totalSupplyRaw": "32918682790000", + "totalSupplyUnits": "32918682.79" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "32918682.79", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952094 + }, + "token": { + "address": "0x8085961F9cF02b4d800A3c6d386D31da4B34266a", + "name": "Euro Coin (Compliant)", + "symbol": "cEURC", + "onchainName": "Euro Coin (Compliant)", + "onchainSymbol": "cEURC", + "decimals": 6, + "totalSupplyRaw": "72706988330000", + "totalSupplyUnits": "72706988.33" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "72706988.33", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952094 + }, + "token": { + "address": "0xdf4b71c61E5912712C1Bdd451416B9aC26949d72", + "name": "Tether EUR (Compliant)", + "symbol": "cEURT", + "onchainName": "Tether EUR (Compliant)", + "onchainSymbol": "cEURT", + "decimals": 6, + "totalSupplyRaw": "71235330330000", + "totalSupplyUnits": "71235330.33" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "71235330.33", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952094 + }, + "token": { + "address": "0x003960f16D9d34F2e98d62723B6721Fb92074aD2", + "name": "Pound Sterling (Compliant)", + "symbol": "cGBPC", + "onchainName": "Pound Sterling (Compliant)", + "onchainSymbol": "cGBPC", + "decimals": 6, + "totalSupplyRaw": "34076968470000", + "totalSupplyUnits": "34076968.47" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "34076968.47", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952095 + }, + "token": { + "address": "0x350f54e4D23795f86A9c03988c7135357CCaD97c", + "name": "Tether GBP (Compliant)", + "symbol": "cGBPT", + "onchainName": "Tether GBP (Compliant)", + "onchainSymbol": "cGBPT", + "decimals": 6, + "totalSupplyRaw": "75066546470000", + "totalSupplyUnits": "75066546.47" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "75066546.47", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952095 + }, + "token": { + "address": "0xEe269e1226a334182aace90056EE4ee5Cc8A6770", + "name": "Japanese Yen (Compliant)", + "symbol": "cJPYC", + "onchainName": "Japanese Yen (Compliant)", + "onchainSymbol": "cJPYC", + "decimals": 6, + "totalSupplyRaw": "91977287100000", + "totalSupplyUnits": "91977287.1" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "91977287.1", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952084 + }, + "token": { + "address": "0xf22258f57794CC8E06237084b353Ab30fFfa640b", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin (Compliant)", + "onchainSymbol": "cUSDC", + "decimals": 6, + "totalSupplyRaw": "38601011267000000", + "totalSupplyUnits": "38601011267.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "38601011267.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952085 + }, + "token": { + "address": "0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d", + "name": "USD Coin (Compliant V2)", + "symbol": "cUSDC_V2", + "onchainName": "USD Coin (Compliant V2)", + "onchainSymbol": "cUSDC", + "decimals": 6, + "totalSupplyRaw": "380017953834", + "totalSupplyUnits": "380017.953834" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "380017.953834", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952085 + }, + "token": { + "address": "0x93E66202A11B1772E55407B32B44e5Cd8eda7f22", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Tether USD (Compliant)", + "onchainSymbol": "cUSDT", + "decimals": 6, + "totalSupplyRaw": "928784229000000", + "totalSupplyUnits": "928784229.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "928784229.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952086 + }, + "token": { + "address": "0x9FBfab33882Efe0038DAa608185718b772EE5660", + "name": "Tether USD (Compliant V2)", + "symbol": "cUSDT_V2", + "onchainName": "Tether USD (Compliant V2)", + "onchainSymbol": "cUSDT", + "decimals": 6, + "totalSupplyRaw": "530001062485", + "totalSupplyUnits": "530001.062485" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "530001.062485", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952086 + }, + "token": { + "address": "0xcA6BFa614935f1AB71c9aB106bAA6FBB6057095e", + "name": "USD W (Compliant)", + "symbol": "cUSDW", + "onchainName": "USDW (Compliant)", + "onchainSymbol": "cUSDW", + "decimals": 6, + "totalSupplyRaw": "0", + "totalSupplyUnits": "0.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "0.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952095 + }, + "token": { + "address": "0x290E52a8819A4fbD0714E517225429aA2B70EC6b", + "name": "Gold (Compliant)", + "symbol": "cXAUC", + "onchainName": "Gold (Compliant)", + "onchainSymbol": "cXAUC", + "decimals": 6, + "totalSupplyRaw": "1007568265651", + "totalSupplyUnits": "1007568.265651" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "1007568.265651", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 138, + "name": "DeFi Oracle Meta Mainnet", + "referenceBlock": 4952095 + }, + "token": { + "address": "0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E", + "name": "Tether XAU (Compliant)", + "symbol": "cXAUT", + "onchainName": "Tether XAU (Compliant)", + "onchainSymbol": "cXAUT", + "decimals": 6, + "totalSupplyRaw": "1007568265651", + "totalSupplyUnits": "1007568.265651" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "1007568.265651", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 1111, + "name": "Wemix", + "referenceBlock": 112065356 + }, + "token": { + "address": "0xE3F5a90F9cb311505cd691a46596599aA1A0AD7D", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "11014520532789", + "totalSupplyUnits": "11014520.532789" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "11014520.532789", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 1111, + "name": "Wemix", + "referenceBlock": 112065360 + }, + "token": { + "address": "0xA649325Aa7C5093d12D6F98EB4378deAe68CE23F", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Tether USD", + "onchainSymbol": "USDT", + "decimals": 6, + "totalSupplyRaw": "168569642765", + "totalSupplyUnits": "168569.642765" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "168569.642765", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 8453, + "name": "Base", + "referenceBlock": 45754953 + }, + "token": { + "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "4374380611328711", + "totalSupplyUnits": "4374380611.328711" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "4374380611.328711", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 8453, + "name": "Base", + "referenceBlock": 45754955 + }, + "token": { + "address": "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "decimals": 6, + "totalSupplyRaw": "23301271161496", + "totalSupplyUnits": "23301271.161496" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "23301271.161496", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 8453, + "name": "Base", + "referenceBlock": 45754956 + }, + "token": { + "address": "0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105", + "name": "USD Coin (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDC", + "onchainName": "Wrapped cUSDC", + "onchainSymbol": "cWUSDC", + "decimals": 6, + "totalSupplyRaw": "11000000000", + "totalSupplyUnits": "11000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "11000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 8453, + "name": "Base", + "referenceBlock": 45754957 + }, + "token": { + "address": "0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "11000000000", + "totalSupplyUnits": "11000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "11000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42161, + "name": "Arbitrum One", + "referenceBlock": 460893941 + }, + "token": { + "address": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "5732089638330937", + "totalSupplyUnits": "5732089638.330937" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "5732089638.330937", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42161, + "name": "Arbitrum One", + "referenceBlock": 460893954 + }, + "token": { + "address": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "USD₮0", + "onchainSymbol": "USD₮0", + "decimals": 6, + "totalSupplyRaw": "995151040492349", + "totalSupplyUnits": "995151040.492349" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "995151040.492349", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42161, + "name": "Arbitrum One", + "referenceBlock": 460893966 + }, + "token": { + "address": "0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF", + "name": "USD Coin (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDC", + "onchainName": "Wrapped cUSDC", + "onchainSymbol": "cWUSDC", + "decimals": 6, + "totalSupplyRaw": "13000000000", + "totalSupplyUnits": "13000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "13000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42161, + "name": "Arbitrum One", + "referenceBlock": 460893974 + }, + "token": { + "address": "0x73ADaF7dBa95221c080db5631466d2bC54f6a76B", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "onchainName": "Wrapped cUSDT", + "onchainSymbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "13000000000", + "totalSupplyUnits": "13000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "13000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42220, + "name": "Celo", + "referenceBlock": 66398494 + }, + "token": { + "address": "0xcebA9300f2b948710d2653dD7B07f33A8B32118C", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USDC", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "19007517220000", + "totalSupplyUnits": "19007517.22" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "19007517.22", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42220, + "name": "Celo", + "referenceBlock": 66398497 + }, + "token": { + "address": "0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Tether USD", + "onchainSymbol": "USD₮", + "decimals": 6, + "totalSupplyRaw": "470000000997000", + "totalSupplyUnits": "470000000.997" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "470000000.997", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42220, + "name": "Celo", + "referenceBlock": 66398498 + }, + "token": { + "address": "0xC158b6cD3A3088C52F797D41f5Aa02825361629e", + "name": "Alltra USD Token (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWAUSDT", + "onchainName": "Wrapped cAUSDT", + "onchainSymbol": "cWAUSDT", + "decimals": 6, + "totalSupplyRaw": "3000000000", + "totalSupplyUnits": "3000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "3000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42220, + "name": "Celo", + "referenceBlock": 66398500 + }, + "token": { + "address": "0x4C38F9A5ed68A04cd28a72E8c68C459Ec34576f3", + "name": "USD Coin (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDC", + "onchainName": "Wrapped cUSDC", + "onchainSymbol": "cWUSDC", + "decimals": 6, + "totalSupplyRaw": "13000000000", + "totalSupplyUnits": "13000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "13000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 42220, + "name": "Celo", + "referenceBlock": 66398502 + }, + "token": { + "address": "0x73376eB92c16977B126dB9112936A20Fa0De3442", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "onchainName": "Wrapped cUSDT", + "onchainSymbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "13000000000", + "totalSupplyUnits": "13000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "13000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 43114, + "name": "Avalanche C-Chain", + "referenceBlock": 84963312 + }, + "token": { + "address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "USD Coin", + "onchainSymbol": "USDC", + "decimals": 6, + "totalSupplyRaw": "545865067327219", + "totalSupplyUnits": "545865067.327219" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "545865067.327219", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 43114, + "name": "Avalanche C-Chain", + "referenceBlock": 84963315 + }, + "token": { + "address": "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "TetherToken", + "onchainSymbol": "USDt", + "decimals": 6, + "totalSupplyRaw": "1847205574047338", + "totalSupplyUnits": "1847205574.047338" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "1847205574.047338", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 43114, + "name": "Avalanche C-Chain", + "referenceBlock": 84963318 + }, + "token": { + "address": "0xff3084410A732231472Ee9f93F5855dA89CC5254", + "name": "Alltra USD Token (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWAUSDT", + "onchainName": "Wrapped cAUSDT", + "onchainSymbol": "cWAUSDT", + "decimals": 6, + "totalSupplyRaw": "362506000000", + "totalSupplyUnits": "362506.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "362506.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 43114, + "name": "Avalanche C-Chain", + "referenceBlock": 84963318 + }, + "token": { + "address": "0x0C242b513008Cd49C89078F5aFb237A3112251EB", + "name": "USD Coin (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDC", + "onchainName": "Wrapped cUSDC", + "onchainSymbol": "cWUSDC", + "decimals": 6, + "totalSupplyRaw": "2000283800000", + "totalSupplyUnits": "2000283.8" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "2000283.8", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 43114, + "name": "Avalanche C-Chain", + "referenceBlock": 84963321 + }, + "token": { + "address": "0x8142BA530B08f3950128601F00DaaA678213DFdf", + "name": "Tether USD (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDT", + "onchainName": "Wrapped cUSDT", + "onchainSymbol": "cWUSDT", + "decimals": 6, + "totalSupplyRaw": "2000286268227", + "totalSupplyUnits": "2000286.268227" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "2000286.268227", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 43114, + "name": "Avalanche C-Chain", + "referenceBlock": 84963321 + }, + "token": { + "address": "0xcfdCe5E660FC2C8052BDfa7aEa1865DD753411Ae", + "name": "USD W (Compliant Wrapped ISO-4217 M1)", + "symbol": "cWUSDW", + "onchainName": "Wrapped cUSDW", + "onchainSymbol": "cWUSDW", + "decimals": 6, + "totalSupplyRaw": "361506000000", + "totalSupplyUnits": "361506.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "361506.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 651940, + "name": "ALL Mainnet", + "referenceBlock": 33419742 + }, + "token": { + "address": "0xa95EeD79f84E6A0151eaEb9d441F9Ffd50e8e881", + "name": "USD Coin (Compliant)", + "symbol": "cUSDC", + "onchainName": "AUSDC", + "onchainSymbol": "USDC", + "decimals": 18, + "totalSupplyRaw": "1000000000000000000000000", + "totalSupplyUnits": "1000000.0" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "1000000.0", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + }, + { + "schema": "token-aggregation-supply-proof/v1", + "generatedAt": "2026-05-09T04:00:51.739Z", + "network": { + "chainId": 651940, + "name": "ALL Mainnet", + "referenceBlock": 33419743 + }, + "token": { + "address": "0x015B1897Ed5279930bC2Be46F661894d219292A6", + "name": "Tether USD (Compliant)", + "symbol": "cUSDT", + "onchainName": "Alltra USD Token", + "onchainSymbol": "AUSDT", + "decimals": 18, + "totalSupplyRaw": "535053697365559770228576548644", + "totalSupplyUnits": "535053697365.559770228576548644" + }, + "circulatingSupplyMethodology": { + "status": "onchain_total_supply_proved_circulating_review_required", + "recommendedFormula": "circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances", + "currentConservativeReportableCirculatingSupplyUnits": "535053697365.559770228576548644", + "notes": [ + "totalSupply was read from the mapped token contract at the reference block.", + "circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.", + "Tracker acceptance is external and not implied by this API response." + ] + } + } + ], + "proofFailures": [ + { + "chainId": 138, + "symbol": "cBTC", + "address": "0xcb7c000000000000000000000000000000000138", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cETH", + "address": "0xce7e00000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cETHL2", + "address": "0xce7200000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cBNB", + "address": "0xcb6b00000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cPOL", + "address": "0xc90100000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cAVAX", + "address": "0xcaaa00000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cCRO", + "address": "0xcc2000000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cXDAI", + "address": "0xcda100000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cCELO", + "address": "0xcce100000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 138, + "symbol": "cWEMIX", + "address": "0xc11100000000000000000000000000000000008a", + "reason": "https://rpc-http-pub.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc2.d-bis.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.defi-oracle.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 1, + "symbol": "cWBTC", + "address": "0xcb7c000000000000000000000000000000000001", + "reason": "https://eth.llamarpc.com: missing revert data (action=\"call\", data=null, reason=null, transaction={ \"data\": \"0x18160ddd\", \"to\": \"0xCb7C000000000000000000000000000000000001\" }, invocation=null, revert=null, code=CALL_EXCEPTION, version=6.16.0) | https://rpc.ankr.com/eth: missing response for request (value=[ { \"error\": { \"code\": -32000, \"message\": \"Unauthorized: You must authenticate your request with an API key. Create an account on https://www.ankr.com/rpc/ and generate your personal API key for free.\" }, \"id\": null, \"jsonrpc\": \"2.0\" } ], info={ \"payload\": { \"id\": 1, \"jsonrpc\": \"2.0\", \"method\": \"eth_blockNumber\", \"params\": [ ] } }, code=BAD_DATA, version=6.16.0) | https://ethereum.publicnode.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://1rpc.io/eth: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 10, + "symbol": "cWBTC", + "address": "0xcb7c00000000000000000000000000000000000a", + "reason": "https://mainnet.optimism.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://optimism.llamarpc.com: getaddrinfo ENOTFOUND optimism.llamarpc.com" + }, + { + "chainId": 25, + "symbol": "cWBTC", + "address": "0xcb7c000000000000000000000000000000000019", + "reason": "https://evm.cronos.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://cronos-rpc.publicnode.com: could not coalesce error (error={ \"code\": -32601, \"message\": \"Method not found\" }, payload={ \"id\": 1, \"jsonrpc\": \"2.0\", \"method\": \"eth_blockNumber\", \"params\": [ ] }, code=UNKNOWN_ERROR, version=6.16.0)" + }, + { + "chainId": 56, + "symbol": "cWBTC", + "address": "0xcb7c000000000000000000000000000000000038", + "reason": "https://bsc-dataseed.binance.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://bsc-dataseed1.defibit.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 100, + "symbol": "cWBTC", + "address": "0xcb7c000000000000000000000000000000000064", + "reason": "https://rpc.gnosischain.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.ankr.com/gnosis: missing response for request (value=[ { \"error\": { \"code\": -32000, \"message\": \"Unauthorized: You must authenticate your request with an API key. Create an account on https://www.ankr.com/rpc/ and generate your personal API key for free.\" }, \"id\": null, \"jsonrpc\": \"2.0\" } ], info={ \"payload\": { \"id\": 1, \"jsonrpc\": \"2.0\", \"method\": \"eth_blockNumber\", \"params\": [ ] } }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 137, + "symbol": "cWBTC", + "address": "0xcb7c000000000000000000000000000000000089", + "reason": "https://polygon-bor-rpc.publicnode.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://1rpc.io/matic: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://polygon.drpc.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://polygon-rpc.com: server response 401 Unauthorized (request={ }, response={ }, error=null, info={ \"requestUrl\": \"https://polygon-rpc.com\", \"responseBody\": \"{\\\"error\\\":\\\"message: API key disabled, reason: tenant disabled, json-rpc code: -32051, rest code: 403\\\"}\", \"responseStatus\": \"401 Unauthorized\" }, code=SERVER_ERROR, version=6.16.0) | https://rpc.ankr.com/polygon: missing response for request (value=[ { \"error\": { \"code\": -32000, \"message\": \"Unauthorized: You must authenticate your request with an API key. Create an account on https://www.ankr.com/rpc/ and generate your personal API key for free.\" }, \"id\": null, \"jsonrpc\": \"2.0\" } ], info={ \"payload\": { \"id\": 1, \"jsonrpc\": \"2.0\", \"method\": \"eth_blockNumber\", \"params\": [ ] } }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 1111, + "symbol": "cWBTC", + "address": "0xcb7c000000000000000000000000000000000457", + "reason": "https://api.wemix.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://wemix-rpc.publicnode.com: server response 404 Not Found (request={ }, response={ }, error=null, info={ \"requestUrl\": \"https://wemix-rpc.publicnode.com\", \"responseBody\": null, \"responseStatus\": \"404 Not Found\" }, code=SERVER_ERROR, version=6.16.0)" + }, + { + "chainId": 8453, + "symbol": "cWBTC", + "address": "0xcb7c000000000000000000000000000000002105", + "reason": "https://mainnet.base.org: missing revert data (action=\"call\", data=null, reason=null, transaction={ \"data\": \"0x18160ddd\", \"to\": \"0xcB7c000000000000000000000000000000002105\" }, invocation=null, revert=null, code=CALL_EXCEPTION, version=6.16.0) | https://base.llamarpc.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 42161, + "symbol": "cWBTC", + "address": "0xcb7c00000000000000000000000000000000a4b1", + "reason": "https://arb1.arbitrum.io/rpc: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://arbitrum.llamarpc.com: getaddrinfo ENOTFOUND arbitrum.llamarpc.com" + }, + { + "chainId": 42220, + "symbol": "cWBTC", + "address": "0xcb7c00000000000000000000000000000000a4ec", + "reason": "https://forno.celo.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://celo-rpc.publicnode.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 43114, + "symbol": "cWBTC", + "address": "0xcb7c00000000000000000000000000000000a86a", + "reason": "https://api.avax.network/ext/bc/C/rpc: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://avalanche-c-chain-rpc.publicnode.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 1, + "symbol": "cWETH", + "address": "0xce7e000000000000000000000000000000000001", + "reason": "https://eth.llamarpc.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.ankr.com/eth: missing response for request (value=[ { \"error\": { \"code\": -32000, \"message\": \"Unauthorized: You must authenticate your request with an API key. Create an account on https://www.ankr.com/rpc/ and generate your personal API key for free.\" }, \"id\": null, \"jsonrpc\": \"2.0\" } ], info={ \"payload\": { \"id\": 1, \"jsonrpc\": \"2.0\", \"method\": \"eth_blockNumber\", \"params\": [ ] } }, code=BAD_DATA, version=6.16.0) | https://ethereum.publicnode.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://1rpc.io/eth: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 10, + "symbol": "cWETHL2", + "address": "0xce7200000000000000000000000000000000000a", + "reason": "https://mainnet.optimism.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://optimism.llamarpc.com: getaddrinfo ENOTFOUND optimism.llamarpc.com" + }, + { + "chainId": 8453, + "symbol": "cWETHL2", + "address": "0xce72000000000000000000000000000000002105", + "reason": "https://mainnet.base.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://base.llamarpc.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 42161, + "symbol": "cWETHL2", + "address": "0xce7200000000000000000000000000000000a4b1", + "reason": "https://arb1.arbitrum.io/rpc: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://arbitrum.llamarpc.com: getaddrinfo ENOTFOUND arbitrum.llamarpc.com" + }, + { + "chainId": 56, + "symbol": "cWBNB", + "address": "0xcb6b000000000000000000000000000000000038", + "reason": "https://bsc-dataseed.binance.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://bsc-dataseed1.defibit.io: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 137, + "symbol": "cWPOL", + "address": "0xc901000000000000000000000000000000000089", + "reason": "https://polygon-bor-rpc.publicnode.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://1rpc.io/matic: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://polygon.drpc.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://polygon-rpc.com: server response 401 Unauthorized (request={ }, response={ }, error=null, info={ \"requestUrl\": \"https://polygon-rpc.com\", \"responseBody\": \"{\\\"error\\\":\\\"message: API key disabled, reason: tenant disabled, json-rpc code: -32051, rest code: 403\\\"}\", \"responseStatus\": \"401 Unauthorized\" }, code=SERVER_ERROR, version=6.16.0) | https://rpc.ankr.com/polygon: missing response for request (value=[ { \"error\": { \"code\": -32000, \"message\": \"Unauthorized: You must authenticate your request with an API key. Create an account on https://www.ankr.com/rpc/ and generate your personal API key for free.\" }, \"id\": null, \"jsonrpc\": \"2.0\" } ], info={ \"payload\": { \"id\": 1, \"jsonrpc\": \"2.0\", \"method\": \"eth_blockNumber\", \"params\": [ ] } }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 43114, + "symbol": "cWAVAX", + "address": "0xcaaa00000000000000000000000000000000a86a", + "reason": "https://api.avax.network/ext/bc/C/rpc: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://avalanche-c-chain-rpc.publicnode.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 25, + "symbol": "cWCRO", + "address": "0xcc20000000000000000000000000000000000019", + "reason": "https://evm.cronos.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://cronos-rpc.publicnode.com: could not coalesce error (error={ \"code\": -32601, \"message\": \"Method not found\" }, payload={ \"id\": 1, \"jsonrpc\": \"2.0\", \"method\": \"eth_blockNumber\", \"params\": [ ] }, code=UNKNOWN_ERROR, version=6.16.0)" + }, + { + "chainId": 100, + "symbol": "cWXDAI", + "address": "0xcda1000000000000000000000000000000000064", + "reason": "https://rpc.gnosischain.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://rpc.ankr.com/gnosis: missing response for request (value=[ { \"error\": { \"code\": -32000, \"message\": \"Unauthorized: You must authenticate your request with an API key. Create an account on https://www.ankr.com/rpc/ and generate your personal API key for free.\" }, \"id\": null, \"jsonrpc\": \"2.0\" } ], info={ \"payload\": { \"id\": 1, \"jsonrpc\": \"2.0\", \"method\": \"eth_blockNumber\", \"params\": [ ] } }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 42220, + "symbol": "cWCELO", + "address": "0xcce100000000000000000000000000000000a4ec", + "reason": "https://forno.celo.org: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://celo-rpc.publicnode.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0)" + }, + { + "chainId": 1111, + "symbol": "cWWEMIX", + "address": "0xc111000000000000000000000000000000000457", + "reason": "https://api.wemix.com: could not decode result data (value=\"0x\", info={ \"method\": \"totalSupply\", \"signature\": \"totalSupply()\" }, code=BAD_DATA, version=6.16.0) | https://wemix-rpc.publicnode.com: server response 404 Not Found (request={ }, response={ }, error=null, info={ \"requestUrl\": \"https://wemix-rpc.publicnode.com\", \"responseBody\": null, \"responseStatus\": \"404 Not Found\" }, code=SERVER_ERROR, version=6.16.0)" + } + ] +} diff --git a/services/token-aggregation/deploy-to-vmid.sh b/services/token-aggregation/deploy-to-vmid.sh index d42a21c..683c868 100755 --- a/services/token-aggregation/deploy-to-vmid.sh +++ b/services/token-aggregation/deploy-to-vmid.sh @@ -26,8 +26,8 @@ log_ok "Built" # Package log_info "Creating package..." -PACKAGE_ITEMS=(dist src package.json package-lock.json tsconfig.json scripts) -for optional in .env.example .env; do +PACKAGE_ITEMS=(dist src config package.json package-lock.json tsconfig.json scripts) +for optional in public docs frontend .env.example .env; do [ -e "$SCRIPT_DIR/$optional" ] && PACKAGE_ITEMS+=("$optional") done (cd "$SCRIPT_DIR" && tar czf /tmp/token-agg.tar.gz --exclude=node_modules "${PACKAGE_ITEMS[@]}") diff --git a/services/token-aggregation/package-lock.json b/services/token-aggregation/package-lock.json index 1bed3a3..ee03c4a 100644 --- a/services/token-aggregation/package-lock.json +++ b/services/token-aggregation/package-lock.json @@ -15,7 +15,7 @@ "dotenv": "^16.6.1", "ethers": "^6.16.0", "express": "^5.1.0", - "express-rate-limit": "^8.4.1", + "express-rate-limit": "^8.5.1", "jsonwebtoken": "^9.0.3", "node-cron": "^4.2.1", "pg": "^8.18.0", @@ -3309,12 +3309,12 @@ } }, "node_modules/express-rate-limit": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.4.1.tgz", - "integrity": "sha512-NGVYwQSAyEQgzxX1iCM978PP9AdO/hW93gMcF6ZwQCm+rFvLsBH6w4xcXWTcliS8La5EPRN3p9wzItqBwJrfNw==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.1.tgz", + "integrity": "sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==", "license": "MIT", "dependencies": { - "ip-address": "10.1.0" + "ip-address": "^10.2.0" }, "engines": { "node": ">= 16" @@ -3941,9 +3941,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "license": "MIT", "engines": { "node": ">= 12" diff --git a/services/token-aggregation/package.json b/services/token-aggregation/package.json index 066fc2e..1e64921 100644 --- a/services/token-aggregation/package.json +++ b/services/token-aggregation/package.json @@ -13,6 +13,8 @@ "test:omnl": "jest --runInBand --testPathPattern=omnl", "lint": "eslint src --ext .ts", "backfill:historical-pricing": "node dist/backfill-historical-pricing.js", + "generate:supply-proof-catalog": "ts-node scripts/generate-supply-proof-catalog.ts", + "generate:live-uniswap-v2-pool-catalog": "ts-node scripts/generate-live-uniswap-v2-pool-catalog.ts", "generate:route-matrix:v2": "ts-node scripts/generate-route-matrix-v2.ts", "migrate": "node -r dotenv/config dist/database/migrations.js", "example:partner-payloads": "node scripts/resolve-partner-payloads-example.mjs", @@ -26,7 +28,7 @@ "dotenv": "^16.6.1", "ethers": "^6.16.0", "express": "^5.1.0", - "express-rate-limit": "^8.4.1", + "express-rate-limit": "^8.5.1", "jsonwebtoken": "^9.0.3", "node-cron": "^4.2.1", "pg": "^8.18.0", diff --git a/services/token-aggregation/public/token-logos/gru/AVAX.svg b/services/token-aggregation/public/token-logos/gru/AVAX.svg new file mode 100644 index 0000000..610093f --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/AVAX.svg @@ -0,0 +1,6 @@ + + Avalanche + DBIS wallet logo for Avalanche compliant wrapped inventory. + + + diff --git a/services/token-aggregation/public/token-logos/gru/BNB.svg b/services/token-aggregation/public/token-logos/gru/BNB.svg new file mode 100644 index 0000000..fdb806d --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/BNB.svg @@ -0,0 +1,6 @@ + + BNB + DBIS wallet logo for BNB compliant wrapped inventory. + + + diff --git a/services/token-aggregation/public/token-logos/gru/CELO.svg b/services/token-aggregation/public/token-logos/gru/CELO.svg new file mode 100644 index 0000000..31805ae --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/CELO.svg @@ -0,0 +1,7 @@ + + Celo + DBIS wallet logo for Celo compliant wrapped inventory. + + + + diff --git a/services/token-aggregation/public/token-logos/gru/CRO.svg b/services/token-aggregation/public/token-logos/gru/CRO.svg new file mode 100644 index 0000000..b2c0abd --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/CRO.svg @@ -0,0 +1,6 @@ + + Cronos + DBIS wallet logo for Cronos compliant wrapped inventory. + + + diff --git a/services/token-aggregation/public/token-logos/gru/ETH.svg b/services/token-aggregation/public/token-logos/gru/ETH.svg new file mode 100644 index 0000000..096de40 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/ETH.svg @@ -0,0 +1,6 @@ + + Ethereum + Black Ethereum diamond mark on a transparent background. + + + diff --git a/services/token-aggregation/public/token-logos/gru/LINK.svg b/services/token-aggregation/public/token-logos/gru/LINK.svg new file mode 100644 index 0000000..b7d60a2 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/LINK.svg @@ -0,0 +1,6 @@ + + Chainlink + Chainlink mark in DBIS wallet-token format. + + + diff --git a/services/token-aggregation/public/token-logos/gru/POL.svg b/services/token-aggregation/public/token-logos/gru/POL.svg new file mode 100644 index 0000000..7c5d2b1 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/POL.svg @@ -0,0 +1,6 @@ + + POL + DBIS wallet logo for POL compliant wrapped inventory. + + + diff --git a/services/token-aggregation/public/token-logos/gru/WEMIX.svg b/services/token-aggregation/public/token-logos/gru/WEMIX.svg new file mode 100644 index 0000000..3f910c9 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/WEMIX.svg @@ -0,0 +1,6 @@ + + WEMIX + DBIS wallet logo for WEMIX compliant wrapped inventory. + + + diff --git a/services/token-aggregation/public/token-logos/gru/XDAI.svg b/services/token-aggregation/public/token-logos/gru/XDAI.svg new file mode 100644 index 0000000..4ab833a --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/XDAI.svg @@ -0,0 +1,6 @@ + + xDAI + DBIS wallet logo for xDAI compliant wrapped inventory. + + + diff --git a/services/token-aggregation/public/token-logos/gru/cAUDC.svg b/services/token-aggregation/public/token-logos/gru/cAUDC.svg new file mode 100644 index 0000000..e9c73cd --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cAUDC.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + AUD + cAUDC + diff --git a/services/token-aggregation/public/token-logos/gru/cCADC.svg b/services/token-aggregation/public/token-logos/gru/cCADC.svg new file mode 100644 index 0000000..ed91cb1 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cCADC.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + CAD + cCADC + diff --git a/services/token-aggregation/public/token-logos/gru/cCHFC.svg b/services/token-aggregation/public/token-logos/gru/cCHFC.svg new file mode 100644 index 0000000..4d4d53f --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cCHFC.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + CHF + cCHFC + diff --git a/services/token-aggregation/public/token-logos/gru/cEURC.svg b/services/token-aggregation/public/token-logos/gru/cEURC.svg new file mode 100644 index 0000000..63f5066 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cEURC.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + EUR + cEURC + diff --git a/services/token-aggregation/public/token-logos/gru/cEURT.svg b/services/token-aggregation/public/token-logos/gru/cEURT.svg new file mode 100644 index 0000000..a47ae61 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cEURT.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + EUR + cEURT + diff --git a/services/token-aggregation/public/token-logos/gru/cGBPC.svg b/services/token-aggregation/public/token-logos/gru/cGBPC.svg new file mode 100644 index 0000000..92e4833 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cGBPC.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + GBP + cGBPC + diff --git a/services/token-aggregation/public/token-logos/gru/cGBPT.svg b/services/token-aggregation/public/token-logos/gru/cGBPT.svg new file mode 100644 index 0000000..176992f --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cGBPT.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + GBP + cGBPT + diff --git a/services/token-aggregation/public/token-logos/gru/cJPYC.svg b/services/token-aggregation/public/token-logos/gru/cJPYC.svg new file mode 100644 index 0000000..46cc514 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cJPYC.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + JPY + cJPYC + diff --git a/services/token-aggregation/public/token-logos/gru/cUSDC.svg b/services/token-aggregation/public/token-logos/gru/cUSDC.svg new file mode 100644 index 0000000..b7cac38 --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cUSDC.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + USD + cUSDC + diff --git a/services/token-aggregation/public/token-logos/gru/cUSDT.svg b/services/token-aggregation/public/token-logos/gru/cUSDT.svg new file mode 100644 index 0000000..3a27a1e --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cUSDT.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + USD + cUSDT + diff --git a/services/token-aggregation/public/token-logos/gru/cXAUC.svg b/services/token-aggregation/public/token-logos/gru/cXAUC.svg new file mode 100644 index 0000000..733f40b --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cXAUC.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + XAU + cXAUC + diff --git a/services/token-aggregation/public/token-logos/gru/cXAUT.svg b/services/token-aggregation/public/token-logos/gru/cXAUT.svg new file mode 100644 index 0000000..eaf5a9e --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/cXAUT.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + DBIS + XAU + cXAUT + diff --git a/services/token-aggregation/public/token-logos/gru/chain-138.svg b/services/token-aggregation/public/token-logos/gru/chain-138.svg new file mode 100644 index 0000000..6d7fc7b --- /dev/null +++ b/services/token-aggregation/public/token-logos/gru/chain-138.svg @@ -0,0 +1,6 @@ + + + + diff --git a/services/token-aggregation/public/token-logos/ipfs/QmPh16PY241zNtePyeK7ep1uf1RcARV2ynGAuRU8U7sSqS b/services/token-aggregation/public/token-logos/ipfs/QmPh16PY241zNtePyeK7ep1uf1RcARV2ynGAuRU8U7sSqS new file mode 100644 index 0000000000000000000000000000000000000000..389411dedd8f8af94a73845a1f0ed89d39f3ef5c GIT binary patch literal 92252 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

p9y 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 z�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 KCQU}}3I7MzOhu{y literal 0 HcmV?d00001 diff --git a/services/token-aggregation/public/token-logos/ipfs/QmT2nJ6WyhYBCsYJ6NfS1BPAqiGKkCEuMxiC8ye93Co1hF b/services/token-aggregation/public/token-logos/ipfs/QmT2nJ6WyhYBCsYJ6NfS1BPAqiGKkCEuMxiC8ye93Co1hF new file mode 100644 index 0000000000000000000000000000000000000000..3d6ecf97eedfc69d03283590edfd821fecb50b09 GIT binary patch literal 92252 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

p9y z-rs?Y505Jyf7X(C2=|YV`+fJ;+uuBBqycrZ4|fRhudrz)yA#Kw#@^o*S05*#GxeFB zM}LdXIq`I4lV*11;Z>3{pY6~5GQ~tZ0qS=eyxQuEA(u}W)y{LRUr(WJd&wxdoXD8J zjP{Hm^yG4Bn+o@ASUZ|3kuLavIm60A#31h}(+FbqUjiz0a!?#DR0U?ZBxHyOHRRtV z8m*6lC(e0huv_!&0k_rYeH8M*qn+F{l?`tW1*!Q;!V+}aox zppxw2VZ##Fu!OHKp|S_>EcQ>tgh*;QJ# zlJ}%xEMB)#Vf*d@M-Q{Ae1zuzk-z14@O_7i7J1rB zrz^8-2W~oa-k{F)>CmkKMBgYIm~wKgM1;m8kmUvWRKD2aoSW?*U|Qqe=FcQWw}ZWD zQr>-UnDWzAZo^(ONFP^tQ&We24InhEyu&2P=~N<-5$Qnk?P9Lf(|q#T&C9w7^RN`C zH7nN_m0_157o>-!>)D;l7c|B1Gk(6fTDvzX(#VMF{V&xv`lX)P32gm5io;%nA?tDph(_syCi4fIZY&&PdhDtsyL79h!*I*B3y@ zIl@Vfm2Dr4<=oqgAeSSqmO@9(p)J^Nw43t@zPDIK23ypeUbM}0wW#g_Ofo>9rqBsu zSX=b#v52Mpk2(q}iD!Q&NhmtgvbgI(T4_9pH_E{Y6bQg8LaAS3jX*%E)qAAC-Mk<7 z^s129$E(cmAlV@6ClOQfWlWxqC4)J}IcQDu{EzxL6-q^o>`Uzz)H82Gm5K)0vH$KJ zT8rqtO2vLs?-9`dDJt#D+reHz=CT_M(Te>{zscz-$AhB)?V-)0^`N_%QP-_3Z&CwJ zP(C9~&Z=An^?~oVq^YB97G_!6x~05SaP7ns^X&JgZ_RkD$+C$CgQ9R8HkJt<`}k*A zt@z5-1ldRl90AQY) ztjF)$4}oR3)4_DC`EA#+Rt373f=B1Fqd&viF}T9;NBn!Dtb2__?ZcjKeM&-aXz%>! zyUc$>Z*abjXspy9+WOh%H_*ZogX;K_1=YoM@GmaZcjVdzbkx8|F8Ofv^{<4d0+cr!Du(ZA__A@7%FG0F}_5=bPu_zAfOq1GvQ$>4 zB-=EdS4q^UvjADg&*uz;#xY!)qc-VBf&AV|>-{*R64=#LJ;xdt=u!_|RHHSjC3DTT z9;@0aA6%a_3yf_?7K+o!NF0){a%2(?do0##x1`zNF*b++Bs#8=;RHt(q+;I1BN!5j~@y{Z#v;d{y7}zwqEzdn*haV)3h5j>BhU}sdE&4YS|*Y6~mWm z#V7YAco-d|C962jd>os5y(NpbO7srPCSQ~;-^M!2dl=NsPyUyVcLyWTJuWxCwg^Xh zMG@KEZGuo}qt)GMVdI5|=`V^^79sH ze4I+|J{Dn)>C+aq-N|P&Hd#yjWh=?T-)$68iwMSzrCqD+dy@)OC*H@|0d?IOhqE(3 z?!$u}N|#>|1JunQC-O1X;Ve6JC$VT%`FVk!duQIblz{7c>Ho2G)?raT|JPr-lnyCD zy1N?$5$TX_1SF)p76d+kv~-t*N_UrZcZhU%ckDBKf6sOKKi<2uGw(U)bZMt!g=jjX~EqLIB;(;$xn5XKV~5) zQKAPIB(tIZ&BjTIti)pu`P6WXd6G_r#_9Xwm|SH5S?d*b&)-=yW5hGY6F-SoXMj|c z*{n@(6#B-{Dm`ivd<^R&X{Xw8T|w^q7)*c@IdUFHT88d zF26@Qkyua#r3b6r$=^Jq@y|cEfriC83|71;CVAz!#EB|isWoAeHI?L_I;rAlhaOn} z0g@{K)z(#!V{nV)^sD4vR$8HXU^MCZAOe~Mf<~f0bF%m0%Mds6c_9Z00*C_TXMZk~ z=B7yEO&_m2aw>!m#|2(&k5;4z083{qn=pm! zjDvLt6a6gEMIm0phd%f-5I8Uig=Ye6;O&2N!PjyGP_F!RJ<)LZKn&STg6+YSC#X;- zq=cD@;mhF50^*gRNmoj#7Sl>icjSuqffbLIq;IsgagR!Q>zg#6)!V@gkLH`KnyK}R zFblEpaSDQii{e5UI9#zP(qcyGm64x;N?&6tv37wPT|bd1*T>?i3mx)rW+B_j>scdJ ziHj6?2~A1vPHXgc71&r}s1@vfr<_@wKB{9*q3jI#W8p-Eo$N~&d`T5Nc-#vwti1M3CjSZPQEQCgsDhxc1G#tU#J{2HcRG@|{i{wAcGuFo zRPUdq9g^}FLii>`H_|Irb*<-*lFVcl-t)Ws2oj3`ajAxwy3n!^rGWm9KkJB zgAAUY*k#l>oT?-&J~XxBef{A$EwPSTM_*n(nUBKvNlj-->r>Yd?7}b0!sHt z&=1eZVioI(yvd!@qd%{&>ttW3nM+IN#2G(W6%JuMLHqx5?@iQRKXJ;S=RU( z_c6MgW~o6ab3c=t$uB|d(DhZdJHLLFC*_Tr{M?J3R0%&(EWud|ZF=qSg>4JWQODlS z6+PeUctmZiprV~Bc(IP*%Xy196r!(Bz~2;aSl-O*Mc~6yLtZMDZT_mWQbj!3G-esK zej`qVm5*OZxMihs^Z~dv5gWs3 z2j+#w9Em6Vdbr?1tZfq1jQ!24h|IrXqrPBCVP@Q#8(Dxp(x1h(Jza&NAb_7YK4nq0 zzYS^`LLDOE25#D;2>0P}o94}5Jwt^E(f`4qCC=V8BPIDHzcZ5G9fXb;|ApRpfW>5= zT(LL^j-hZE%D%6dhsa9aB{&n`UA$|kW4BN^!GIS`RP;457#J{k#OZBv+(xP0p^sGw zS6FVr5$_8GOo~{PLo_U*ed5*dB8_3PP z!8#2Wy0Bi1NBm&^>;B=!+LR#RBAs4MBikEVoeY>pc56y=SIp#9J)|@8;Vdn@K8>|M zWVU(SHyooMzKro7ovVo+Kh}=7LT&&{-7+&1l!hTvqN5qgsvVBj>5Ls870IzuOA1Q z+xLqMQ7kk@bXk0y1e$x#xy04aS{v%h6g&NaLI8}lX5X5ApnTdm`w*`P%LiyTiC$eO4;r457`fwJ!i9!*09j%C_&sw_krLRn}Sy#_Z}SvyZ@Px z9G#bh+Wemwz>>^mP(_H{*#AraJ5tv6sA4$X<}WZ`MPI9l*}tgYMi`oK_{NE*O7GV~ zbfHV;9!;*eESrOU>&VOthYZHwULozPJ7SbSVYIGRGK&gd-%1`;JuO*fZ+HQcEkVh4 zqMa(j=`xeFTR=}M5y4?{6S8S*FJ~zB5I>DrN`+6E*50K1Ui~8qRc_n$EYydo*9~+| z#hN!iEr@>$Xe4Yz*S{?L$RdjC+z;RNR^f7&H8UQbCXsFQY+{c7)BhQG27A?tLJLAP;K|OKI*5YSj|%MR<8WD9g<=u z!E;|EChpqxq;c7zsuv=SV+OPeP;EVPME)wylX@IO2)>W$BFbbc31@_`#U=&4+VPLz z5NqfC_y_=%$Go-6nn_i0Sjow8=KTb@QI# zB0w_reWcBsdYeBdOq6{#Flm|ApB!pZj;=HqLRi%IaBZ*2DKq zWd5g6+mJMZXJ~@Y64N7+=9MKrV8y)F7mIP$+5XVRT0WSiK4E)s72wIPuw+x158N3F z@l|_OW`SE^SDF?{bE~eU;#!5nn2yZ~PDR9|EwwZOa^|{m*W~NKUZh2n52~mE0ybDK zNv#FK0Xj-F5~O<9cDW+b;rgqw$pT~DtZ;}m(q|pz0eeg*B!m!_)nUJpxyL6pRpf4` ziF-lolfwpOcx&&G@ggYKSD;wJQ)gIqeEIT2jkgj{OoBX;bTWl8GzA9fHw zKKl!&b{QiXtZ1to*q!ZLX*L*WRwe<8P>u4*;Ru>NJ+&$+G@LH-%uBGkisky1+!!6$uM zHXd7l;!TiZIhmS+>_hRM)45A5!%w*39vbld)N&YtQGk()|VW_P$D>X)uToZT0(oGj+Y< z(W-4^tRu7$tFq+#Gl~AS&?{5@`XjzJ-Aa#-lqv(t5^0Xg+@7u#!yv&+Rs=4C9${U? zdKSs{pv`w>h*KDV7HV{CuDx~Q9{D93sOJRUH`JNeJZ1gcKOK*Q zi*|blq*&yi`IvF-BdZRNH)jfHqv4Lo?egWd)^Olt2A4S{Y7x$k!gk3fJJ%K9u#fT~ zhf3%&s5R?z=bmG3Q{u>ODDYDbCYTi19_T@8Cb|8Flt!(0byUqf=}4SSMsU*uHBF_} zae59Tzn-j`dDIJk5@2#z3l029-{@6+`kkCL0>%freELRJBmHsOKYO2dMQ!J!Koj{r_>hACO~B1tosk?F$azO(T1P`y9z2vn+h#p1~ucGDh(?0aO`sY;Frfxa%A$cRYvsI1}Sr?U3|E2alWkAiz-=;yC-V(>nORYp9$Z-HDF41|N9JPg3@k z;sk^>3GLLdKF!G9MF7>m9Qs)$&cynC*o@Li-3wk1Opu84) zmXkAD1YXo}7mqh`a#zADdA+`TSS*`mzq$f0KSaC!K`JvbS{>vh;P7%Rl2T57*o9@v zEh`~ePqGxEhd9JvXh!L*$iwHPeMSa>7I0+FQzTnRBy!uKv@+54d(Z6Un@|FY7qt65 z%Th-=I(hMuBQ+9T?^|WxZC7K#cyK^{1=k7suLX(!Zl9Su2?EdcCf#dHXq}AbOB3QE zquOwzf?9K?L!&Fpq<7-^Jun|;un$GfYLWgkEOm5cvoN6(QV*zPMRfZI!al&F7Q2vc z%Mw30J;lSjCjQawG5ZRcEAcYpNfZ*{UYTSl{xF}6i_Fk#Bsjm6bLK~m0r?2`PhG$V zCgxj~mKBUWK!c!J`*>uTvddglvxsEMwemH8+;VSKn|XyL9^nJLJ(#u4!Mxis7OkhzWa(d>``0?^Z`hr&u}49S!Dx3le^~z2|E1{?ILZ z81Jnxbk}}I{ATuvLMb~Z@d|3NTAK`S?1D@0uE}vYE9QGEuXyS6Z~Y~AjsN~RTAM>j ze_bhWLyZQ=kBw{uaw-h>+XGh%jPg$xhDllCJLk7EF(svP*~n|&_r6e=2a)$b%8c$f zkw6Bb$M4*Z6X7Rwesi#GCeQ{7WMynG6P+VgcJKWSB5z+Qe7q9QRIu*$n2E_89Jx-e?E;Wv%D^#z;g0^p5+ zJUF2s%_^2A(htn!@hH}(=L=bHmh0_`V^&LM4PtP>N++WU#lb_gUfD>e-IhBtKE*JQy6P6M8 zzMd;7q5&O9a6m#gNp)TkMffJwBJiE84X0k;;a4?WNDMp$#?U6o%+ucT?fEYB_Eek= zdQ$d~$DV+F1HLv@Rp++L zwJ)~#l@noBv>j81`xmMo(%eD>u^!f7llKNozH{4E!vQtC<{!w=<#w7)Ui30d&iiX% zz|PlI&ajo}QInZIX?=kjy`03InY?cEAmYKvL*7Q(NSRQ^0IKnhZHK#Q2BD;}_+%y% zN_sFhi;I*-l`hmh*%`o{cT1r>>aP!y_bkO~%QFch8>{``Flmr2d_(@B_kAc`U4z~| z!L&b``xBvf>3A^0N#w9;xK^QSP2W8xajq@r>pk=)*IJlWhBHlV7yzlHjBVEQ-a2kJ zaet_e%ItySXF>+wgu?u;C0MRg+tK33XK~&JVDqnB96s=Y&)Onoe=78y0-X&q3T{Z7 zmLo9w7nCdt0gm=Dr>E<1c~jb#wD!hdlzL0DE#b`l@j^OnC%XnQkzcY0>W`5VzEICU zNyP~vk!8OoTWx=FhF==Ez<{2_Y-^0$!Typx43Qx=_dNOUvSRTzj0-)OT*|X4dU0N( z*DZ~ioZHRw{6ipVI2w1&%FscS{GT|f1jE#G5BIK+eFVR&>|W(#ch6(hQ9`H!t*!pH zb1w=zU%PiCg9Ox=*N7mtein;q(hC43xfR#EZM7KK*Nd8hkuBJnxZ_58f*m zx4diqz<;!|!|ekcTiRkoE<=8&FLO0ntV~;TXvNhHDZ>Jji{w?n(I8kdERdUNXdAQm zU11vSFt4UL+$LSYZCfAh3y6lVwaqUq0j&j@ZNF`Cb$6EGu4g@Wu<$AAgYq@^nFc<3 z9#5h0g=TB?-NS`sv^&LBeI4(o!X)m#Z>MV%cdt+1GVZ^%8nr$xa%kY(yb!rus>ed6 z|JLA*L46E_|GG*&>Rp6HQI-WMdEt|)F*+7g$$lSZD&~0KW!mcLVTWX=6$W(-7kF8R zjpRadLUt^gPJKsvrh{A&!q|KE`?A(@2<76xWFev?m5uPZH5mF%Zkek-6B+%NwBKBP z3cNN2gylSVz^sg1VCJ=BqXFTCzn3QpB7L+I`tygIBL9fbR@dR651vWlEwh{F!*3Q^ zUX&;1fBrSB991Hpnc@6PWmVxVa9Yy6q7diy&3)>Z3dOmIhQG_Yn6sI*5=RYtDUpH` zV+vlwtaNl+#1I^N9H#f%dT$#SebNsFNFe%Z^DEdcuQ%w*v3!0}T^c=JU;T@IvOHXa z<}$%z`!FmQo53?I%*VpU8_x=1g<0J?W&DBDk7WUda6;Lu`Qdv#KPd8cf9XE{rg`GU z<#zS-trADDi>K)qJZPl)4e>PL3ywIb}GbRWTj2WZHD+8kmM z?#W=(H*ZQCC*8siPLM{hB!N?Q$1q6s{PR-{L5PY4B45O|XMA$A4Lgd~_$b>P6y;AO z3(tbCrSRir*-dm6t5Kdu=S;oeunCWT?3CZ?G|8ygaetr&|^*Tkq}H?z>7g)xM_ z`B%SFidhKHTpA8&=pZB5j&>gy0UikmewoILaCr)72$CBICz(p-Mbe1*QP!jj5=N@i zth}n(x z-}{=Yfwc~7Oh;$V)2HR}n{6eGNn02=*MJDr8;$bt0M?QC!TIWXfM@dW<8$}c>0|5# zBT4gvQ^!QzSIim$g92S?f*WyW%Bqy;0dKpwp5;M)63zidG6uBa3{IDKo#9d#Bg#!= z*dch^qX0&)OH^Q|VUHgU3>#D3!M{v>lT@qEAP`SS2+`M?dv^&D@F0dBfk*H=MZu1R zBzOOPGVF%;|Jxt&cfP%Ay$t_D%FbpQ#kgV$jEn7U=<>@f+9^6XNxm= zGz0v)*Y{}yOcyIy;>XN^Fi0js_i8R0blbdTV7SOi6SF+(Q>; zQ=41=8ar;;{@81`wgZAzkKX`Dn)yAIk7oHSZ9ZPM{`A-sDrNoqZIF? zJo_UQHjTItFTb`M>{Cyd)fuGv(;mPHBk%9dIr$fVm+(}dYB8>Qxviw-ztHufdg zTgwOau~2E@m%@eb{g}SBe9C&$UIV>?-FI5d+Q-AaUwd!pyWNI{q~%U^uKm{(DOSdK zEA8p&+&`~wWA5Z#x3IC!K(jiQc3Nbw5bPPb21&&YrHq>-?}d>?!=9EB9C6RF&BALh zpNAi#cH-xyehO-^qk5!P7Hx#NbHGXU@tQUZ!^som_6OMscn}(V zdoGKA{u7n_0y34Qp|0Y?d_XL5G80<``0b*}DpEJsBwxG73$C2E3h&mO91!5Me}Zf! zT%yb;6GuBg%he3nR=ZsC`PYB&ZR7BVU14!W$Xr-zsZT?JwW?w4e~7>evzc z3-Ej_)=Jv{XISF=Ma-nsie!maZo4{rZmn&0RA*W77EoQ!w_Pysygts4sQgM(87z+O z(X%ElxG#U=kcoa#56!B0IZiB`juEu}nu$CORVE-iHim$X=jyXN&ypOtcxkepq{W=X zgs)gpzChe2t9m&p0WwyFS%eW>RhUPS=rkyi0&Y$%H0R-O9Z|Va&)X~8KS-2EIwLWG zz%yi}sfkqkhg$8ED}xP;C>g^|V9~eUy{7n)dFFgMl$<#uR4d7*xl!K|B<~f9-&wY; ze?qYm`Zj_gaH5t$A$D~BDb5?yQBi17FkEMo*Zq2J?lJAqmIii z3Y4A03rfTtBxn@g-c> z16*@araoM)>Mp_~(ItPY$u~o?t+TrSVqqWFmNhcZsLVd>V(!EDP0v<57^H$oyhZ!; zZP2Xd9@t+!`$s0p()%4P8^GMzT(t}*-nI;4#GywV^jbFTOhmBtvO-NO7<;>m(>4Z? z4BU9(WQLp8yd4{}0wNvrR8@hiEvs+tcGqM$Y}|OG!5(Fwq~%7v8>77nHyB<_psp#u zPr)7rTuKil!*T8~kZPw9LQ4J zuF*=y=45Ea%d3|$UyMoTyj0sBn6~MliLQ1CD66$_5EWy$Y|b7dZRoXNG9F?FU;^~DkxA1F95X!L@A16bL9=E zY`MwKiGX`#h#$iJSyrs6JUQL8Qvk9;GS(vi-#&hM^Lw4S_v@s-J1|B8LkQP$v*Nx|XbyWjXte15JY6GcIn5hg5mLWa00&!t`h_{eB`bQ3 zg0v<>z;;up7IVf@Ucy%uyG9L~Uf9yxNgr3JXz(AluXyt-l@z_6Z?dIW^{N-;aRQXg z+W+cH6~6vXG~mOX8(XhVi`bJR2*)-Qq@Pmfd1f4whn|MQXjO`c6eM)1pfDB7hDIX^ z0Fa;MQ9t+TJWMDb|I<3Lp${~?Px?4_ulmx3Q2x;fj!@;heEEa&{*t1b#4ocmMO-05 zU7R|ty?+Ka&r!RcIL8$iBq#*)zaGM;-N4sSud+c92&?rb&MQ6%5;uF1M2=3-v7aXC zgZS}iN8YihQqkq^zFO-D0LmKo5V5aVU7`pPul_JL9`kRs2#LT(q{4_oyQRo8*89s=s6t)$lU2D#-|MH z&1FmG|ExN$B=>lqnwsy+M?sFj&$_9O0sH&=sOe3@pSq8k!GAunib`vyB8J`EcftGX z(_Qi zr)EUvmnt{@J#E`j8ZLvCCay-J6a(8QJ3&-mueZzDH-kBb6#nf$%KEB=!YA7x4$U0? zRpe4G4{L1${b; zX5fbvlL{PoQ&!3WpP9TDGzAFh?CbD5u`F`I>3OpFy4PN?i=#CQH=Z*A3vJ+oaccpU^ZC)@T%Lx#~f8CXG7qWWW&d zkef_I$Q#sJ!-e*xgWbDk;W7qnp0zj=c8JwBwQp^@;9{3e_~V`}&wMxOLL9YoU0nKr zb{z|wRsz)<@<&r<({;*xex_FiGlMO&g8-ES0lmhz=ZUX=2>uyTn+R4)-d8nl{_muZ z+jVE=_tBrSptB`sLqvva18VQb2$Y4fpD2JM{N5MK47$K_?{+;=P)3eyI&{C6jr10~ znu0E=g+(;0igaOt;eG#owm_@+Ysn^pGY-5Qp-Fsb-Dxhb%=h)1U5c zOnm;-D0>qluY+V<87TN+OT*;guff%^vT|Q6-uJoji*Ucf*JD;eE+lUNZgH#GCB^)y zl|YwL1;dICPL4(lwOm1Rtt2@^SP(ZGbxJDaH-;l6&v${7`YPpFDL(&K$dgGWwUK>@5C6m>&t!hm4$0{6mDFshDlI zZ~j<9u2P^2550swg`DLK_si{5c5Z%t{c#iwxgtBd1a(6^J-%NaQKRHMP6J zW}CY<_iPn@YqI?+bSZun-mLHlZ53Qu4Dl5^nQ8q~{Av~knuluSJSToS{0-`^`uaVe ztrs}}Pt&LWJ4(;b`**fYmzt)+kDx{AtI>gQWK2rxDEt&%6HIg1`k2?FBa7IUr%qc zXnHnUzY9-C0g<=L+uB(2Q>rqW5ji!EkLsHcv1yX>P$vRylv|B6IcC_vW7$#5^|U+$ z3A1Ql`q3V($XU*`g7X7TA|t#anb1}mP8}hbWow1LunM(Ik!ahjaa1L?T`vBwPVG2$ z{{HBSi!4zWGn(g4na?C?@0S=#=7?Y-&6rwIVX=-7=l!KO zC)@XC1VljQLFC;3C5w)9-6#hmUg;tyzh8(~|dy#c8m zp-Tu(4q?B#>s6dIt|Dqci%AEFI)eYciBJY-;|qD1$qjcY97a1qjJJfkODsS6b)Em#q<2PvzPb;pCdw4*-KGxBz0eEIb5GkQ8loIs+5tyUc$DX7H(L9X1% zAs9m55RK$Akb}3eynI^Cg<(_S1d49Sg`yLdD6(judli{z^IB{@5ikmL7Y=;@cA9U3tt0yexNBn}#q?L>bBQGJbL2nZ1mu$*4oMtdBaL<^MT z8vi+0SHb{|%CyX3Qzbb0>>5GNxG&*g#Gnb70eJUO5*3YP_KC-3e z*e+3*R%KXJ9r0y{2l{r7i_L5=MOtq7MczWc)W-V( z(`w1>@m%ruIqCd_+JpJkCRLt-IKQbZzI65eJ2Em0B!kg2zvgG$p$|}qK9!uHStFF* zoBFEK=iqk^onwfzACx)nOfT5dH=B&7+ckZ84-44#W>x>ee}}Zh5}` zYL|Q^fX|K5$VK|Br}6Xjw)^QuEF?VsBv;fk{1o)Wi^77+QpAze?c_i4u~(}UPJ{wQ zLLwOTN50=F(Y~Cm;mu}lb4Njcq4pQi^El}6Yzg?)08Dj=S87kr!CDyi)!H$kzld6iZC(J>W7?H)D8w}JXU0hVdT|C&C z2ReL|!}OhUr5t+6jv*gz>jr+iDx@8mcU}lmxDGRaB>p4OH@)<4-}2wWR~i?>dN!JB z>kjRjiyym?P1h3HC?)Do(J#&Q~yihKKHOy5T2;(ydVFwI>{i7lML|=R`8N&#=#Yr-l!6-l7n5H6&QEibctw z@*(*HjVC~);#uH~tGXja6kP&32U9qgw`7jSo$t(V zH~v1vL|d9IL8s__=JHg`%aY=@42dz-WktHQ*$o;BR9@aAnzcbtVnfY2o%6+0t5Mtd z@o<9i#(&ZXwXB!O^!(mqrLhICVVP`U?F9`+<)vv7T}i=gVg)n09ii9Zls4IMvs%TK4CApL9C4>njXoDq=%+feb&P>LL+nPb*)jB@)p`57e70zRIQZ}l|mmCrb_k1y;$9*TAn0V6gW>;k3yg0_Zl8nCX$SpyGVWG zMVf5(bSveWa<>uQmhXCRmOV|VOlIi*72*hQk-Rf4@y_p`TtSe|kwe514Rf>Vd0$P4 z=ymy#Vn{#N3gbZ2&Y1L+`I|^P7rYU%5ii1uH?~fPB}B=a#*i>-&{q4)BGo7ZN7Hgb z?P5AJIi9Ok#@a^KrqIzXwA{=U7Tvs}tXp*WE-+6J#)x^?ZI|b1r(o&zpC@OntQ`&9 zxuU%4vSBI6w%CbnWh4hrWYfD5wXt1&2MvY*yW9!#BIB5?@OcBbW+ zQ4n~TGng@lS?zEyv7n{q%%aTg75F@KsfNP?Kp6DNMb6!N-)#`-FyjaUVl>MVPgCga zyA(k(Ol}*D7hR%n;?D(MaP8P)GQ2oR3FTP;7-9$f`^R4Zr zo6kzMx%!rWF)uaIgdmw!6t|@;1m~ zO+so<)uFSgC5+kPHz9{OUL~I;Iox87E5gM)VkWZ6$=9$8q~?doW?kD3BghN~n}lLp zj}FuXa`IOkMtyr?bpKK2GkCKNj4AvTak(2YSC9GLZyHEqtoblrV(AENv1_p_9VUHr zpBz>MqYv@vF$mH<V~~GNs2IHAme#wtsqtN>)`OHRX>1K5AwETptrN z{>RB$R3Aa(?;Aq7`BAF^q79_w>{hDLUb1l z=RX*}a%B%Q2_htC8PJwUe%o@tOxvNou!v>3qi|xLPws5?#v~ulo40OKxJN2s(Qt&G z^ewR7*YTFm_y@jK%=)OHJ(2aqW-=l<8Ep|4Xr5=CcU9}j*WR>&YJie%68Xc=L&hP4 z1kxEa=@Pi8AjuWk9mIkCx3wzQhvxc@*h(|TG&~q18V|E|?u)4r(a7(;gaF6XH27tp zWLc!u{QUG-YHtkOCY7hu-5uRr~`{UM_zSYYSP`No5l=GFe$5cSaF?VqjI6p!#27X}@X=otnnLI%72PT5&v)RxzmLls_af;{{) z*SVEI=dQW;{5pfN(9C>%mt7Rq)$X@lcT-6%A-=x}vtN0)FvQ<$3mR_-Bcfl*+5hC? z?p+;Y(^1fRJURE%?=euAhy92j-TdT(ZMYW9*-3* z92jFk!dkaCdAVjT1D(23LF?Fsd&XV%e<8q#F4cp=GQdL`d~tFgMunc2#Po2g{Y)~$S0f{jK6P zB&~d5ut(Z}zF?Xo<5Xxb-rdUaN7jpF85~5Z9eHDrv-H+`3$_4&@%>94?ctlE&yc~7 zcqKIZVz+QS$fb!qLb&p*(_4mYbwz*fd;3NZRXpK4M184wlsojm?OR@>L^#v{zL~2! z#A+2Kt<9|^CJ0hVR!iC8CsVHr$v;+G>99)z_?w>EJOj+)n!JHR(_-4O}5d~rS zoFWm&6vA>Xfp2+lIMgwt6Vdh~6=W_tYKNJl-9l($Yc{8;+}F?p94SG2 zxYg_D*4NCiWc%Osh)5mEVUjcCRUy$v3V4x#eNQ$1teXYX1 z+4&tJsrlQ+!1PXG-e0hk_1B|=B#7-eTg`J_Y$HQo+qvNW2e8fPOcf)!kidZo@H0W7 zu!^)yE&00k&8V=l!z-s+@A-QC>{ZSlR-&dUom#|^K+x}akd;<;D?;l}NIN*T56ikD z&cYw46|eHC>2@h4c5)r*f?8M?4n44E@3V@EdvUFRPxh&A?)Cdzsu@G@ft&NXA}t&ZfP&9F0SHTBl!Vg!N_?yeI@1-X$Uf|mGG&Bjy?iB) zyd6VOpyfx>!?z6=C#u|#t#>WI5u~4BVoe$m{Tg%#ywS46`!;ehn#J;_ym<>W2ml@E zIV1B0%@dBvtC+4GNtO|vC!}PO+XpG2jhz{;t34w3{0VDHhRqHwyE%5+9z(2L#9M>kCXTN>E{Hto^3neFC(yEUcDof5*)lccH(w#&z~!GB*hkqW@&#(#68qQKSRTMGvT- zJ-)NAkA8MtN)_AJYOzU~2&1V)A9^KDotpGe-l6K-_1Yd39*k}pUhLsV=>)x7)3%l^ zb~O`AW8C~!_!q8l%f2a^{m7L_QsXBa`54k5F~Ofo^v2yH(EKlrY;eBz>)QyohuISh#CEY%8dM?74Rydf`F3eUCW$3q;j7!NK= zFiAWtTs+US7W4OARNRy{f^ks`4ws|;FFFoRGn-WWFJas*l&>2)Z{r=uL0Q@lS;P4a zvlKYNGU38@ooJ6j98kN{yYwQzq~uo^N&@4WT(-u$kV0Q%%a^sD`I0a+`b@ZWxT#gp+tkF|(_rJ1!e5y={-xU7A*YyLEdTny}4Os4DlGt5csvfx* zU;C=j^oG_V$(J}->Q3BQ=S;Q#Av0&J8^+f z25*d0f*21D`d2MBhP%G{1A<42+q4#kV*mp= z?`tsw2YWzxvq8d7Wge9x46Z<0Pg!t(c_sDBjZ1>QfquYnmjO^@k3vwuwaX^-vo zU$pjN{h1VS(ZO7-6q>;*>(;z(0};<>3rZ*M2#*WABGVrtCoQSrf;l1)Popm5$;z@n zNjl#N(u(uPX{<*a%nwn^gij{A976|7irmoBNi$AYqtIhqIVlQ=M@|wKYN(VfYxRNF zZ^DR=H>r*iENir%MwNc?qLG7zB4tvTc0T_QbGeA)X|m@ABs@zIeadx``a3w)27KWj zvmEPgsSH9nHMsE#r5-==_3@EVuxI5HPi~4wUbcrVW<}0biiLk+9)A78`HtHAwRGmp zFLAfhHUU&@+-xMF@G;dhwwSxw3W5I+i!gKko9LK8Q>485ia=y{5%uL|r(38_so3A@ zB^b~XY(**27U!hbf5Z|ceqWeVZfFxV^|hCtm48ZQzjIVUkT}YZo=p+QoFSRlGvL0>^NcC~#vT<*o)LL{JpKKF~&VmouB@35x#oYLil zA+Qc7bBxVM4$J^?a)C;D@tWugS6L{X+O{S0QnDTM!*#eHkI0t0V7$;48_zb>#ACc+ z18-J*6#JU{(+)uqNE6F{IroWH&be;;*G~@eQ;p!E)MuW{pOR^RrFe;y1pAuU-&wBc zsQT$p_sT!cG;couRTmt8S{8uOSy3@|Ct1P_PO2m~PaHYG!~oH?Gy^Q?PUvJLno;6fH2j-0$@UzGF`Y$)`I;73D&Y6t^m~gNy zo7zZ7fHi)0@PcgU=lRxJ=n})Wu{H<=((RXQ5v}y-`^#U&_`pSB%B0YC+E_gIZ21;; zE3vN|Cr6|8(szUi{XoM`rfZ*2=yIZ8TeW*n7Ue^hw{G`Segh51wB(LF81q9QJI;}} z5JI+@Nq`O=VPHUC_pAgnkq$ev;ttC&53nb{^s>~IT*G+i8bs<)eawqpbnuoHFdkptY`Bg@o5mBkguFBKKFHUm zIE?bB%&MFop4+wf|L++w5o3ef=>Ak^^jQ#2>Csg5!h}n#Re!^0zerG)grD*(#ovOA zL!Dxx6s3BPQ~(QdSqc zW?jK$;gInw3*h9o!*@%q8h=h?3 zHFPHNv0d;pgZ5EuM$w3GeKdXFK9ag3KOB;^#FL^G21(nV*6n+dq(|*$$o=ei z@)(^cehwLTcrEk1zT&<@CT_`@u2gRuWJjOmg|x*`hX_zQbY0#gcc^9@Bo{Ole!$q} zz|L(KfUoI0Fd@==0}8ASbxKbMOkaMST*UGr>X_V}jWhqoYual~Z<3r^F$`3|nd|gz zsCM|V;}&NUaqr7OXY4x(t9a(XYU8@3s*0?$&-CUcacUUk0pX!pdVX8o?Pxrvcqh7t z+W%RDVz^1?Po624=j3oiHzdj#e=oLtF*o)RA-dKWqnxp@mu$tqCoWR37-$MarYq3LW0DOsm*vAlmJClFJERfYCpAOU)6j zEs^y$g7IYQZIMWxRR-prm(Ffpg3t4Gt>DTekR$B0)3)#I2J8TXM;Mps)>Hl8sb|`H z-de$q(5N@x=9-a$)&Jw@D%hgxy7n15B&Ayf1cvTXhwg>}hLrA3>29QvZt3n0rMr=i zhmh_P;hXpS2YaqFd+oLES_q~O>q!Ag#%ow`!QMYV^P*p0CJjEfdKnEJP8}n z2fMesos82yV7M3bTbB-BL2?e!ZmMCzTpNxuhPsVQoBI?ZruK(T;xMzJMiBn+Yi`%) z=sLUAMeh8Xd({c9BhB-tHJ8cmgOzTmP(r9Wjam>YE*<{2&f+)90lksga%u>xbk0I^ z0q^Q^X|}QY81^fsdC%)eey4PPa5F;FXCSg5-^7UDo9Bz z@_EeDFURQ<)3AKaV-1<_t4DNtmxAZQ=Ug(ad4g?ifl@LlJ~KZ>GQ16pfaaSf`8-H^RcI#9+T)O2S2%^MMAp&ozzF(wc~9@mL+0 zz+vJ1Ju0xhIj(ux^1dXgSiE?Ys(JR+kQ^0~3!0W&p7#Cl(y)Z}`!wukwNEX?AL1Tq zVIqswBQ!-aDc3?X-+eGz_Ttq?t$jMbbl{|pR+9%d?CPm`9iUr`)m zKLc)IOpcQUyYm-Mv?eWYuV(DWS@;*$+87xr@Hj56U4PkY4VTT0t9(zKwJNMc-{%IR zx+Nty?{OYn@5mpI&UK4x(Wj;BqK$DR!wDB(9r{b632FKNIFwg4*JcrSJ^an~$sm{R z#*>}gRh=AX#U{M|dN#edALjo)W}w)cHBilUCm=hnHjMhKl5{6fkGkT3vgTe|Cf_c8qA3F~84iDqn&8lkXakH@tW5VZZ26 zSO2G|e>=KbF6qR<>gAPixv(AM|6<(Fo-0pteM4u)!OEDHm$JRh+KKaohtq7_y!y^5 zuiWU>8SP?`3d07)5F=vEH(_6_(#I>oNno5*3DZ2iR+T6v(AMC9ZvF-~TUWn|UQuu0 zmc6u{!ORoYtlM!P*d4T3@)}$t9`NmT;y{a`9hZhr9eMfl*GuIB{MBaKmj?L>Iz6x9 zV0Qi}_virwcKn43Xlt^5L7hr!KgMTj%*%bx?@piChB37Mde8%vhwhbNHtz2>BZk5K zX09vMS-UVHj}9(XmiGo3dtqq@q&?mrcXNA4u9bVpFQ*I@1W5P)E2hWb5voKK>AB8` z7A1CE>yGY!wTn*D)`UklNPUShOVz_bzwEHvnrY79UjzF-&}O6L^K1GwkJCxMsbT zwFv#f|1W4p!Gt*FL3t3o^pr+8 zSatj2nYz^D_d%5&`0s5`o_kV&ej4bIE%M=DwZtIXLgXXihoL26+CSu$+u0gXacS-^ z9>o=f88~EksUO~u+0+RZwZXF>Q3VaDiyI3e3<;#I z$P5|qw`=HsJ$O*@n*}|8R7p+kYuvh(+;6urwyM+PXbf`Kvv_=pYo%;wfel=iPudKy zH{;$5dl~`)h*D|(3l7f;Gl<2EXlOY~9 z;5RKHPb6x_pQ~Rcf8-(8g9qCbrx;C5sRmn#LisQgquU&s%K7bAv*W9plb>L9KUlg( z_cT++Q^cz<=FxyaVNz3mKMt?iwqQJp)Tbd@J|P%u!hO z2xb2EhAYVgXIi8-!|tq1?=`&s{7%=t9`&_l?yCx=Xu*#Y125jJzVq&i__zrQ8n*Rz z8^GGYHlP`Xg_Mdg36LJV`9W`GUmiPJz?>u(=^-gh>lpclH!F2X)px!mCrnrPf*acD0yi^=+~o^-*#G-`RE z{_3$UsKN8i=_PEj7u%nT384U={SJ@-XPSswdyGqgFmNE$?vZg-Y)`O(8R8cXhPw2S6Ludo6%w z7V9zCLVYPY0uWuF`V01TvEGiA(nddei}Jhc1}fYA!_yoW(N(`j_oD9yhPw4sN->JX zk5ia}O5py_#7RL(s*@w7cfM1xRqjoJ`)sxt=X6J?Fz7r4^KEC^@L3+=pU@OQLT{97 zOn$IT;4wSa3{L?wSPhEi-~RH514>&t1kc}>?A9gEvbl?ldYy4me<;jq)b`0<#`LlC zC_r+{6{&Y-jsvrcAynDS(nD09(d)4PYAh#LuMS*~ySj+J2 zn}|D9c)ktYzffaiC`lm)OG#Amy0v@$-t`(%{k@8kn0odr5cBA!A3@hf^41}7lo)phC#s=M!`>NihfGNNC0fArbl z&T<2zlec#1Mz%Ep(I}6P?m3Ey;soBZ)!&@kmW^tr$U3DW( zjEmSB%c}#LD!z^Cy0(Qjv0}N~HmL&`@`Au1G z)$Yg2BV$dq3jGC3bAYzUd|I3~JmqTSDk-JPPLcVphaWBrj->FQQ1{U>=HyNT36Sn( zDPl0Bx2BPfp>~+)5%_d`Tbjc8w?l26sPX_9Ks`8z-Ul%irhnl8r<-EQ8|t!Od3fc& zZn$)67+&Xk-S$Ah^|Owjm;|W^vy|aosT$jtvs?Nol@7Aza*GhG4XW8Mh0Hnr+w(N+ zYlC}@qX5gxG6GgMolysvHTP6TK5w>D+Rk_3z>5`(xcPg@t>!y9H!#Xvi?_^|_@b;m zfFBS%b@zJ^yRw|J?bEh>eXo$ydkkLabMsX8uYDsmA$5|+?j9X}(g5-;?zZMdAVS?`J$;Cd{>T$@)o2OfSzgoj)BcCGy zGrjiDlYS@E2kZ$I-!sKKO<S-X7V){@gD^2~5 z)i1kv3L&s0@l%vM`T3EvTUJ3bQa;g@E= z{)FnTfIeRGV;n6GXtF=Hj^Q)Qs5Gk3F*4h1O}#$7s)G)@{7*llRcZr&wPH?Qw91jD zL)@q?KNVAjUq`>D9s}Bq&ov4vv@b3~L@u#T%(D~QLF!A?%(l0=ND80+QHSzJoUA=v z2IOzRSMeS&PkqAf<^|6i#ok2cDogO5{jnOoo=a|UQtHl2?X7QoV_s1CcqOuHtY+*a z^d`{w+Vvj?5=_npqXeB}@_+|KRQ51}ytmPffp@^d#rH`Q8wyGD`FoGj(}Y%f8ob7+q{gxyz(>cz;eL z)&34UTyT?W>afLB&A#J}VxHHzok`BRp@3?^&*+!~3#OV$?yv>~ibszm(1YJvkt#h= zZ~e6r=1jW)IpLch$a8w*WB4rvEXEN{>V79J5>v&S*ngT4P~sHyVbj_-%<^la>7m16 z-JzA|rx8WB|JD36EE%=NTvmB|o1*!V;A38JL8t_lO*{w}>w-h2@qHwIOID1jFhsvM zqr-Im#P+Z+K<|p9tqMDHNZAQ>)E9bT9V)jv+~sD|`SRU-w&3oHWp|0aMC7BaAk{uw zD^vnhst8>C%nLdBqZM80Nd7(2#zT=F6W6k&yDfkdJJ}I8?-$WFv-Pbj30PcWXFJ+FuZ8wp{Zi|H<3P*0dNawh-1X zV3d=ae|Z}eS`eaRAHw>Hl~keFjsLe<*DBl{FN^SjP**sW zbq8*u<)NbZL!4_~puz|OGRgLEesK}|h90LcS{qzxEkKzn8ga@_%GlpIB0-~*+v36s zP_&Z^5R8rkYWGQ)Ajiu)t zvnpfP!`tY5nhaGX`#FC39fdo6YS2nnc<~n|*Z2Eu^i%EV2Q6AE5G}xPwHns+PI;&R zl}0om2)i^;Z5)Dd%@&1Se~lAp)byjM;sO*PN%cZUP~}-BSuS|BSs-Jg^A1{fkksxD zC5d+WccQpWHd4>lD|d@1IafIOE!!D+*epi-&^qx{8!d7nu0iPgg5O5(?IxH5s!Adc zBVl96lSwBGEBw;ur_A%DTm1}0mf2kWvs2xwEDc^t%ORJV3xdNR$I+F>KMq2zlEa|h zYYv#7RLX~x^Rs@4S+Q7s8KCY>L3pa_O=oAd@9e_U7EXNZB3xiF@_TXkV&q-)OiK7;4g~7NKod2;B&hX6q>U#QF!^* zc<#hJn7^0lr?QXN7RS^?5oN$g3?+(#8#mge)TYD{>roXzX z?Ft!hXE6{ZNp|XeuFb+EGyJOX_xYIYwdLRI1;D2QqobnSG)LROv2Hir45bsZUY#h6 zJz7qWujOjUw%|t+=o*FN$?K1&&7*M<{{C}}E=kMH)5+8n&@hI23NYA^SWu~RvM|N! zJ^cyyA*xzgI%>TlTistzBcx*e{Ja}oiws!JA~jfZS<{@(Fo?Km7CMRm9ofTe zAW~=I-Dni{-#x$6+FXe`*zHzz;!M^pKEfA2)$c(EHYg|d#K;gN9-R`SvfGvrwKJHF z=&rr_(Pb#`G#?C?vWA)UU!Hv6DmciBk$7(9B?yuRzUryq!Pj8Qg~=@~MI5cCJBY&u zDdN+_vf92!sO$ZS@lVxkd5PbysjI8U9G4TfPksNApL~;EAyN6Gf(25PzAr`e(T3Pu zsZoK47^7yE#4;4!E+xP11bks%$ThW&PJk3go=48>Prd7aaCDCoi`1~VxB>jM5{0oy zdrF%IB0jO!pfT>{&c61Rry}etk6HjB$0ca`X*~G@?WF;&?ttFnMQeI@?5_b#bde>IE6 z^GZD)6#d`^a=6jkYPhp5#cA}L_|l}0Afgemgz;T@Ko>L{6wfj($M!c(CAJ2I9FY~= z4)CJm>OAX0-a!4e)yF%Gx=Ghc-t9t23N(S*5c~j6B_u{xQpMtb$^rpyeEmy|{GQwy zZ`R-Hbc+5q4r_P;tClX?ql&C436P-)KN+hf5)oBNwwI2`f)`uPGWi#OUPX0r7s59qFJ09O5H$l+I{x7N3xYj)b4Yh#IJP-rj+v$ZvV z)oM(mnGypMP9{=|;?^Rsf3})Q*3iqZYeYP=4)$;U3yqjCZM(_R;_Ix9x9IX(FM!m| zVR?0uyKs#PlKn?vV45Plo@G9>7yKMh^SWm0y6)9_Znf7oa(-@lkZG}ya&DhfagVvz zt{Zb~OIC7~(RSc4bD?jbueGDt|D)h&<)(wlS~=jmIeA_cH-OiAmf1u@$Fzh@^Y8b1 zYAFZ>QzN_{N>rv}{@s*5NyAjWVV39Sgg=Px9HGaLQ8&}?KeK;u;*!>vN<^$``A>*X zW2Pe~p4AHR0cdXAsA_nTtSW@YBl54)qvdI_;+TGqbh*MJ)@Fq(x&5Pnb@OYzwCSx1 zy}Mp-8Zqq^&xjmD`j?Ef|0HWwlA0jmU=7+UBAWsgEjks)cfC<;9)6T9^>z24UcDAW zv=lUz@vN6u>$uT9^x^164c`LH`PEzD*DuVY{z;XU^D{+K&FQ6nXar5yP4};CWPuPX zBlP3XUuZzRL*D2~;}<(DdyhJ!bSZ#i25BRdE^DeEePjcRsUI}A%lB$9rDov zz2rS>$QywSbmF{CzQ)Vb#g=an!HRqBd7!YZr(@KkZ%uBA1w=R8jsq$E#n_7p`lCse zG`7ZGC2?Crh>1fJdDH(U05U&1n2rWund8%2gy!3p+Uger_7_rmN0is)-wb@&;3`iv z#MhtE;(3JspaIY*S@VaJyn*Y67%O{$&HyJ^B5^82+=!J#*|Kw=r$XZ~+|8r3#q$9A z`V!8oM@^)`I%ryPlKCYuy6?9UtbUy-Tk^&@2znY4uwoDbwjA#4$kn+GP|@LO0&k_f z3Gf6woqMCcg}F6pa)Q+85|W~9M;qA=wWDUa6tgeCy?>Qu=g~Y)v`}=oz_w)e{S70u z&uGJ!{}K^ww4JI26UDXuD(6%~efii$bdc0v%w*BoIZRSwmhx$0J?U6?sWarlIB}2M z_TsE`1;BI3>#QBmBHtZoG;$ykT38sMP~LJC5UNYsiPKo{D=+Q9gZliw1_cm5XC5P1 zrUKAKy*_vU3 zm7>M!*CxBz9-VP5m#tBKoO&d28JmUQtxKHsq!A1L)KSF~_5JKk!g!#o%pi z3SZ`F?F)~SLmOT!Zt1Md?dmHs%_4Kh2-crg+ZFD57TJuGh~&nIR|1z1wSTS3b19oP zNALB10o=&*EKvE@$e^|mGJ}&*#nLJn`v@otza&X%=wev(EVQe>FunHG7lmfp4d*&a zKQgqhW-nLwO^5-X^3ICq@tSYd(*S6!D#XS~N`um;lLUCfG z+#|lKy3|8hk4v!WUlj5+4CX3i{w1P8ArHt;M;M1}_V{BE8N#z3wKP6bqcPL1RABic zVl)yf_}Pd@9`GwPGy^iKKww3L8%(j%VtQ~}qS9J?ptPt%~4@vscu9WylV)N(D~4L3~IX3e|X5Vqhu&)f(X2P$bncy=*o2si)z|+Lb-ck zvJ4p%n7(&<(Pe2lcbVM+YU9qKbyEA!DbYZ+E67tCQge?uE{&WB(k>Hi<)LflbZWPp zE(x|yiXX^tR044%4GUb$xy8DN5_VIx0K8hS;qBOhN>~TGVh90^MXiV+AYxOTf5tTl zPHg;A;xF37SUw6laZ`5}&cCjoYWqG~r_9~vP)Ya^k%_o%QyaN0?REBkQ-0GQp1a7D zN$wJCGu_D_tkY>gRoJbBo2QoE|+L9us&a*`~vdS!h!GvpQ%`j_U2@UyM1uK>$1v%hA zo&_{cxzF2YPSNi!47X@0P%y(;Q0h~93LKZXFu@^lCQLmA45z)sU#(K`v(TDV)Zyq)%w{VzkL2~d|ba140%Qe~MtX*2F zA<+rOl|%Yt(1^?rm4B+yz^1^SyE6HMrk!L}vNICXki5Jn&{`++7IhlS6b=3(Q>up^F-Wd(`~99$+Y@Hszi_I$jQn)6$&j1MfQ=l z_bU5?>Z&W+L{rkX-PgLc0sZw;bo`Rz0Dkr(IkKEJPtF90(Y|c(pd5#hK5<}D4&NeQ zrAM3br22UjL@<-W#%6pItJ#bRYujNETH(*k>3hb(Avc5~B1c-SNa_BRK-Gt)F zHTlh#CU#zb=EXxt8RN5MRAK**WlqA+XPOLW)AQeApxb&Pf?PN1uI3e-k;Csv8<8E#)onVN`1hEsEHbM zQrlRrtK~ng-uRBS8i4oAkM(!|IaUYAe_uvOyCs|;X5Ck};p~G+Dk9n1-oQcg3{Ag% zG74ZS$6iwDpMz-oeA+g>^>w{cH1b!!lBPZ!={&-aS@ig{S$i)&CIO27I=hE|pGqJF znpaezonKVd5Yi>kPJ`AZ)Ng2`W;IT%zi6jTdR4s$WXMJuZMiapRcmbhUe=kpk+$sq zubV~wAb)F6d01CTR=q4LfW+EMH>R=D1pn31DW$`kp3hU4Q6hX(=-{JC>3HjSB2>TX zU7YDIaX2rk5gU1PqRJ>T=o0{c(~@z3ecE76iKKUwNVCMS$XAw!@z`{aaxgh*fa2fH zzk$xe>bTB&un4+8my8DkUW4}hMY}%z=Ul&<)aJ)BIDRm^7KbJX*|25c?`mk^gwG}R zDR3bfpgU!dnuo?W)ayOt)%V8}n@C>>`1>x`rHe6^$AQ+r6^wR!9tb?G0xjNQK~K+SD#W=cklQg z0ptA-#|7acy%P2xl2CE}CWh&Dch-vo%bnz(vp&6c6%jmMH?ts~o(%o(`}8_&q!k4> zec`64K3`iHSwa)Geo>ofGN?2esm>i2uz^{;CHOrZ9G8|_dsW6;S#<12^l)ppekNcA zX5N3~AC||jLeH=ZfG8r^#?8qYpV4+?a;spRek~<-+gZdjI-*R?ji>w!(p}FY?-XWh z$?^K5ce;G)_5Z?#&tuD{l0KbjYj}zQ)F65UDpeqVk?tKyMMX8S@^i(fm3Ay%aM4Gb ztkiL`wLq(;hriBZe|XTyL__ClzPH*2zjlvc(Q7sVHT63sYcNMlSHhdGv4Jb-bA0nU zeBXYBqf-B;qu1O}8y8FqGO;=p^T@)FQTt>5P?=KLU5Qxj`nSsU{MBqc1<=!#DJ8CW zHEbH>QL9SCPdYDGMBn--s`;9x7SQMivwkjW;?kEb z>{b8yfZ4M`m}Ft8-W1t z844)ZW8(rOMQ!xJwh-aj1z(+#2b)ijlqYujSg;uio(@@ib%+z}Emp}{;S|jqa!QP{ z-M7hur1jdzK`zoPZyFz5N*{-|+uK&&dh@s1s4V!H>*}7M;HI=HW&pnMy!e(l(=H`afZ+4M<(UeU+L1~wcWXmgSTT9 z*IDOEYE-sU5$nFVs0m1zED>3arVqB???gG9@XaRTn^P*mu{D@2h4L=yZd3|n(Jzir zuI~hJszON`d8jb!+9{jqd%LaJ05-o-{GE6)oa1Dgc4w34S4LZlc)KpkgH#;Q_P2QS zD;bz|850vQy{8tw)iN}#UO0Q~d0~I{*=Qk(&$BC<00c0kU_a7AgDlUR@Lhh^SkqmQN=0yVx zr@M|aHy;fJKn(0K9>*tSg8@gLw^V&R#0Nk7RdhyD2l;qVGlWQ&P)D^Gt`r6Bm{eMy zdQxWC^#_O3Qagzx3ABTd_1~SkiW)EdE1qA#?`=n~sZs`jl%*SrtT~%6` z-z!1Dp_6kZHvxzK@O}BOdE}-782|$fe6#`I7Fg*jqJ6aKQQ*8)2u`P0A zzK&TIlhCTHnybqcJoeq1Wn6)g_rl7osJ~&ba0^B5kJyjHRVFgvc2-%!CjleMQP4TU z>N4MB3@ne3^R_4o+~!5tH!JsOmJvzy^S8jkg_uM-HY%y~&#WX>2GKqlF66n&N+Hu{ z`-xV_Z>Tc2%TRx@2mfeLwDf{jb@Kcx@} z91qF38FDp>A3wz;N()+XR=5WJhxMBuxa&z~EZvy`-GeY>z{NW#jOT*(V}7O-IPVD6 zD5+eJ1Ob^@g#be?t>6=d>GSVvbT6y)AM`M$l>~-2VvY5gvb!JqqKTR4Szg^M;gUL2 zF9j%u$Ci(pBhR>}Tf#M*T!By2$C#H6t?)TQZJScNBpnYqN?UZBQX=qiS-a|`j$Q+~E-U1^BvU(KeksEorr1NCtQZpm!~fPc@dpO8l}4i* z0+xtLElftxOhe`0dAEpHmSS_|D%lv+D2{FIT>Nu64r2e6g0-nj`JbFg7ec@>V~%_~ zsNB!rUoTVk&!W*kjJf$jttdzvA6sr+~UtcD0|<-gU`{eBdFRenrrn zn;BwNUM3PFvTW%edXV>eg!C#Wy9YNMHt%d779fkDymDlqTdBmg@Tj@1ZX%v?Nc%VNlB z7Vv%nWQ+b(K+q&IZQLu+5G6mLM}cKo|pERS^c@JVLK`2{_Vx4?hFN!15G~JCGThNEVX~?vs1kyLLhE zuJ}`TnHu`L;VPMHwV#eqHL{wG$U44tjnj4rJcgAkYGOzbd;(j+Y4Gpb$RRZ}cmJaIKO`>>G(w zxw1tqlz2s;R`8f zVidA3XGYt{brq4a?uoST((N5}FQ$sEPhK*~IJ(76v-fx4zt?eDZesjz)8ED9BlER! zvFJYDvd_g5+6?IQw}vpC3uP%m0FHwl(e5VAg(%;>r4qjF?J|(zM~{e4zD9`_rLaD` zeV>e9EmcEUyBhm&WI4z$&250gHM^!l7VIPn!_`|tu2q_QdFlrvd{surO2)!pY}Z7D z|E=&<1mCW}RtRkB*btT##G?aS1ND73##Dl!TywN+Wb`fZD6Ahu({yTMU13&D)%=Ru>a` zJE;y9oO}13^b~pc^_v)RHGXaJHXyDc0rC+2==LL9^HV7j$KRHBD92JB0nEiLaG76& ztf&Eu&72;t6FFB>r?MRoS&nPl{I+~9ed1oMU$u#0IfVbl*3mlxVFF4{Q1@U%A`ecC z3*79=xjLe)=sYCE7eUITT5AgA|G~A9*1N)t8{pLypvCi_4& z82)90oOD78tPJbZgHlm9F*NSOm(EATPG><8;eZs2Qc1Pl^y*riIlaYhP@(8#MRW|R zF6VsgM{-sfe_iR zzjd?7ddX(6;dr?D4&^ydwnW1^x>+4u9qTT3_x0U9T*(ZtO7>|dx3ta7IRVvNpwT9# z$L?D})?4}FV8wkSs_rClH?eI*Z7+7#qGA^g*5T-t%uilb;Ui?7gx*SSi4n}R+0{At6kE^?{TfLbQ^8GCTsu9t#*vef6$d9O15V>^%6mkJ zH+l`&6UQO=)3S8r@gW&>iE4r8bQjSXosL({V^mcg;pQ9!$Wc}9!@K(1_E~Yx23Z#H z@(0&>&1%;p1VLJO2Dee?#aCs!R=@+p zApzqqS{x{a;8}kBaAq1)DE*UT`wpe#d zsJM}p4j#B|cEFOjf?N?9-M!&9T9Z%0G9(I^ON1&MBajp#@~={@5`LMrN510vT?a&d zNaQ?q1|SIH=2DQGjlY%`Ic(2*WHNoU;T!+kDbzr@_Q%-*9i5nVcxp0zZNVGujIXE~ zB+(;SURDFTG~91~R0q>6x+VoE75o_lok|2Dc|{`Iv!frjrx8;oas?jld5cm!YI_sT zpUY0?Y3VgTI13uVT>&G0(KF+YXYIUU4fV{cjM8YfzYfTsA)dK!Ei*1kVPPIKyvjAt zE&E6Qij`)7BWt8}pucWMXphd^0@+d;vlt}v*DmD{7V(h5Qv!rZi_G$dTvzzsWy666 z%(AO964~>C;y1^9lmG#7XB;N>SJv&fH@a7CA8-c)e-JXkoYu{k?R|125(VMy!KsY+ zA%iiLA8`xMa``O8r#_cs46BBntNWvpAbE7Dy48Q}A#o;kec!@+4vM{{H2bU;?%KC> z&KU4d+iCwh%4%wNyL<8GQ zhDL>Cgn*#fER_@vuL-C$#jCv6RY`e6p`1sFtVz`Cf}Wuh2rW7~H+;$KVvgc1bFj-(y&vur<$+<~{dpSBL6kaCOT{(R59s0xjvVu`Yrcvwsv^*$9oqwxnF2$P4xOc#7gRzp7U`gTs^c_6>v59#}z8i-K zJ>2DfuTh99X>|oC=xzxVfWvuqid22oVh!doq@$T8+JB@N9};--#0%~|d-#e&G&-9| zoT#L4gxs3|9O$fQevDaRG!MoSNxp&$Ot7>ylVk~#$zn9WOVJ$L+%32N&AW*5nAhhB zgoXqr<0qn6)#B4S+l6;Y$Y&aVFd9Ne@;z`}zK5Z(ZqrJ@S+7k^Bv{=#wrAs87x;Yn zKVz0&{@hck*|64Exz3Nv=0Kh`eqQc9#inUKDRA&#I`Pi#7yV2BTS}nH@IwCH+8of> z?k26>0Rh8U7IiM90g}#uBPDSAGhhrDZUGnfru5*GcY@0oHR;!pHwulq6}IlG6?fli z3D>6mDtZ3<;$f|6fzoLZa8S`m`)=B<1@V6Xp?;n4#<^t5QePmq$W_0jTu036+Jq1P z17aZbW)%c?0>L2`IEv^_fs0aHiL5v_h~kR6fS%AX%m#qgl2aS7Mj9gJa42%m5-N0^}$@e;1IbrXoL-LNO8tmIK=N{ROjM ze9eO8oF?GmIA(|fv-uw~p3vLjAzsuKXJS?FX2tMDVtI#t##gydy6YlE-+ANRx6q?4 zpUWE6o^l~%)6t+8k8Nd)KF#7<9{v(T5m}B}K1CaPhn=!YIU2-iLDbr(TllB>!>^cr7lDr58CU;Kbv1ZMm^r`$~HD~nG^^G#I8vjsdd0nyRG zv&077mjO0<6ghi2KGFcJhrauwt1tHA=qfk#redXy%T)&?^Zu1qp7}b#1Z+>fCB0k=QcV7P+kIot31KLV;(?zvH@D`+R&!WRb$*ZZ|nMk~B@KONb`zr`14&;wE zBJwvFD=Fp|-aw!kQAn+p^LCv5i*b4=z2`!F%Uj`RB497$`_Bu{L76*IQm2{nE(KF` z+OpX{Li1fk$S{8eX1ILxsU^JhMbDV&~|d!vQ-g}T+nblkax3r zMG9P;!pkzrEDED=Ucqk^OCn{z3tp`m#CQUx0A8ZP#ekT)KJOvLt6yoCU9?hZem@dj zB#$18z5OtVMGlZni}7UPN%pr>ACQ0Qj5tD_;dchEwAge)T5*C9Fy7Q#7|>&?2`}!< zE~m2e@^G684@Vvj1!D2XsbThPYq0L^E?gTVKQ5fnX|E-F__X6_qwrS(^wk zRrR$$Xb#&xY8-OK3Z?viTF(dEt`k3GeGPKUJ6`v%wZs9!XGeWW-ux)#{1^#U+rJ*t{=3{6KyZ3 zE=?T1+5FrZbjjCS{Sx5p{KeUy?ERFwD%sU6#{|pIGW>?@FOxGI7XQ8Rc<#^BP$(7e zH*%U|ZX^{m;Kv!JGK%YNvvE@Z18OfU4P+@1ET8uo1$Oj$+6vX0Q>x4x z={IPzsq4%Bwb$O$S=N1jkaAb)rOJDgUfCGn3^TT4fO|${t-qVASt=>>Oe@vb<`yJiW85->G$+?A#+)8*is|I2Cx63pQ^<^_P1KlpFulqap3%lP3iq)P zT{c^iog!g5L@CjJBIv^}_*nBdk;s11!5lc*(MNZncHyrUb${W$XMW}vGdlT{1{f_2 z=7Xw|ZzO~j4|NQ<#<0A;FgGFYan%l^gLVk_0N(!K{SJ3A-hghHdk zbek`^dLako9n#}den_Y_^%X3@pVeN7cE&74wo9d+Gu-%CJ?qxEfNtRSsq#>|-2hkQ z&z&*s>V#(xE)^zZs$5EB`Ci`GPAsg_KKd*2gBZc#s8BN(hHk!%N9M)u{+_>Ydc)hL z=7ntpoq(OH0!IDc9vP$zW$(sfuO~{2>$C`=6DfdNH4_MFo&pFbB*)jZ0BYk2!>nLw zKxcwn9udK%FoWBeqR6`Tob$$s7Zc|9DWGyWMH}FI@4gye{PdKqw+Ck&6V#Aa%IsjA zUj)hapZ6D%r;jfkhTuqjKZKQjYhmqEJJyvgmVS&(U+f$g54!shF+7E__i z>5jwk@s?RgQ;L1s>~OzOR!XP9)FDHLGB&=_5VG)kg#At{5+)UOvBZ&pllw@{H^+6> z23eF&QbkowPN0BR$Q%4eh236^ySe(+BGfE(OnwDmT|un_d#e5usy+f}_N-BQCj&yt zKdX4L4UH;jsH6eU#zy6-xZ)Y)=4@!wm^`J^n#2L|CIu?C@TBI1bhkA&xa}lkq(*|M_B+CyMOZw26RwX$Oe!c5@Yc0gei32$ z|7$E~m}tBH{<$tzb=s{I@hqdYG8<3YG93rzjI?8Ojwq|&zY>JJJgoy8NH2n`EtPPQ$C%8py_|d?Hl>#F!o5<6{&TJTi?Sh{w4j%d^kSp|FbEiC+ z5f{^d{q}!ip&84}z{RHagsl9w_AQ&DCd>*oYd_2hnz$bZEh1)k#O{IT&vys%ly4UmmK4qS`%+~GT)KQCc3H?bM zoYEB-&>2qbv)5YRF0Tn;wX0>_OMCrH zH({B1a4wUs0yBFSW0yu8QE%#5qW!hVz~=O(_g>#VELE!x+W(^Hc``$C4!w`J{IhUu zY6?TrriUmkG?$hZMeL$~G1l?2c*262_1NQ_#F@OKhU6GmD#Jiz-Mg>Wy%k+7U84hi zj^_Q95NXp4`YnSPp)q5z` zq7{B8u9a>2=mBp<^7fC|NT7~hy>Sn!PsA(xuJ>*P8kS>iQrA^q6=8&~b%kygH|Y@~ zzeGcULD-MT{Ngu9kCi6JfLu+t`oy$vgzkW}b0pF?aImAZ_lzV#-iwA=K&oP?RinaQ zzci&}Dj*+Qp^zeGWxhg3l+tDLDv!=oqqGf1$YEuOXr4~JELlA_=g^kZExhr0bZRB9 zS&Bjb)u{Up$-j|!r^HfQ;digWR6XG*y!2YxE~{-$>$<{LW#&>gO zTh~t!F8!(`#RHLQvuXPCTgVWZL>bBN_&FD)|J9WcAj~N{Eu(5cfQx2{CVDs`PT)U6 zpPrrc{PJC9$a5UWi!fFK)>m0IxWhiLd?5~N!wcOHiV9alXJ;7LC-ir85 zt588w;pYDi#-W?bA#|9)6!?kv)pqzKZZOsN^zS1DoKWe! zl+Lu}InhiJ)M7RX^23^e*#Gy` z5hZ5OEY(RPqI(PFl5yu;zGM60;GRw80*4b)MOh9m4MBl+6r(i%JTTq1t*l37y598k z>%Ths`OyOrRI97s^-p^&uipR7Civ~#Q+uR-mrg!lorrn%D{WBEy36V% z%Doe_t%+u2KJWFo;U>2>^D>bSFfWeDf`3@`-a#tNw$i@)YRsIN!KwxrFFDnVu-4JprD6g?lRob@zI$cA-8iF~7`+{$0_8|f4Cidb)CsZ* zPlXGj)0($WqJu0FV!0mwUq;HcchEUuWIg)}+eBxdy&t4DSNAwshjc!^mA#hNP@lG} zsufJ8{@w*`Pu&>8`f64CstFk#qeJ&s6bOYS%rdiunPnBX^Dfj8I6B8=?D1Rr(2uj5 z>kp!OJZQI;;};J6)yV4$4+rcB-uBS~Q5g$)Uo zKk=80UH$L-@#)cO>T+?a7}~kFOB0lK$++J>aTpo=2|jnQ4^nzD$0+@C@Ld>;j%$Z@B{&b? z6?a&X$E=m5tI?pFg0PQcNc079_uXb1$}gr zgjkJVH%cM;TWfNpCjgJ;R3k#m_xhA4!{QyKZ+^5jIayR+gIZX>kZW32s;(}AFH4v@9Xo7`LZFp@m z6C87YmTwBV5_7RLJhQ6LGSB4fzW9HdB92Y9t0*B?d&!09uPMW%2U5RHV%-SQOEByY z&2LL<#iMeiW}HqCc~O4w?H%5(z}ez82N(;L;5+bo)tok2|5*&y6c^M7N2l7a>k;EsH~ZdkC>*qAPX(kgeYZ+ypLFi~IX}-PY#WO!Klfh4uJFLCt0EvP zaQk`VX(~py_4$Pkj2v6Kv8VkLUK{$@@41e`=7PEpRQuB#I@R)rb8rTBwW7IN_?%w{ zq=fI+o_z@!Q_L5Q!6XQj>D^0${1c+G7~z%QjffWY8fHv2n7U>J*ul7O9qMg+%V;K| zy%AH&17|eqE4`#|o<56+d2_xhr$yO|&?kHm{8!Y$1Mx~vmTpY-wUh(1#plvw4<^j^ zzZFoz*Se}t>nh4H3{xhTis3syVz;%$)j+4P8EhLI_?*pv&x|}xUNil2SmjA!GxHNi zW!QF*Q)FeSaPWNUV^&LzZ)n*8#OG1uaa0af)EBCw%vZ!vf!~?Vd}<@ckn+(-K-*x- z#y`+{&M1s^-#?wX>L6`tFNoFc&3}ktUdkIs{mhP_r0qvXZN zN=ou4KOmm9ST3{Hha6^Up3NH&9o`V?g<&J+iQ=G$`{?)OA1;Zt^J!}iwyU)Ss>_uV zQr`*nL}gTCqd?uC6hBQmSgZ%{!+V$;H9V4v+T=9*!|+j{PGRY*tq}Qwr@|lhpJC@* z`+fiIocDxBr*_H3Ln;Cri~n}x8^pTuCfNIj$#&7;%@zfd{a1r&BX!vW{LLU-F_QjF z_BC6z(p|-xvq-ZOgB}>;*n$;?=Wg>VttD|X=iq}{IjeN-iO;2@K58EtL^-XOCg;ub z#4fzb0h3RZgV~=LMpNG=0SoL0y+y&0FE)o{9*pP&AXwaP|Er?)TDO{dja3f5f^p`+ z&cK_6|NKV*{Rcu+O#6$*o7kUU)~4Zo#|ciusjLY8HH79a@frT)vMbs8OV1&yoHG#+ zqf}Xe)murfB|7Wov0e#xacDSa`m4?cOo(H-sz>gJeXN{BWX+Me@dICZ_MN~csVJR- zgRxjy$5v|lC?^_&YgL!Ta4GWfX??m<_lPtWtzn3!z`3meVT9+&Xw}U|+;d&%I~zC; zZKS66xTocfHy|Lm$fRoyw_*CclJP56~F4F=k&YocwHYeir}S z-;~ynI(~wtyPUM`YiphBeCW{Iok0Uk8js>z)}$svuK|BEKtEmjMG(c5~eROdMHvJa=Z)l;t-x8q%#|ZB14E|7)1YkVVcW2 z4APEQ=*(nbB=i5$RcF-Fi7Sd{oNd+LO|h~URA(BYD(4kfUx{C7b+Rvzt++D4%@L_1 zJS?X*$Ut0R!O*R!p=&8%R;lYehDV)y? z@j^HY&q=JpG+Sb{s;iQuRAjf!LW_5DelHt`6p9sbK1tS{1E#yPHU4}1ZYH=kT6Gcf)FGeJ&X8+!*Nh$rSpXvfH zfg)hYnUTMyKNMvUQ2Rs53&Bk;l&N!!j7HtZ?ZgOIslT^MSG{;&1)8EZXUVMJMSmoi zK|re;?J=6X(JCllmIZrH_X2?pR|Ml~UI{(k%q{h4CGPj{%O%4no<{Tne6eh+-rQ5q z%GXX~QNYwL*IW^KK4CH^*htXQA^huIU)V+!c8YzPkBzws=M6x>dCjD zCA_!*wSQmOk!b>n=evAe?$Gjs$u;I+x6cwX5>xgBSSF=3NJhj)d_5f9s$3eGnmFQr zad2?UrHbu%nRrQuBI35)ouCjbsH}}^C6TiOlLgqO(->A#iVA(z_U%uPsOsG2C)xBY zq8(`3`z?Jpu3L!lMVv-%^NmvFU+_Jz@M>Nm3_{8VR=~v-M!sF?j~+iM z$7Umh&O0Gi5$)A5_jFEr|rF>QZLF}Xf^hzl<}#1JO-h>g_7 zg?Fj{{DEOwr71@5Ui`XaW8-1{MCE01?bm=@a_d(grTw&cngMI;k>Z1dS%p)P@(8 z(3}~InDT^oEdtnsfQn|I z1yPRL>OW19OUG}qG6m z&4Tlld(N$r6lCZB*nIujMTNw#w2hB@8tmPH%4v;)rI*6fwB}XOtzmDmtZeq{y>GVB z%N&c|4?s-m6nXUaYxeiVkZTLv;@&P1xIzm%V6CZ`=y#S-;=qZD{;NXiwzj(jRY~O773y-0B&I3-{hVvgC>_X-!)rdfNln%7?&Z0=%GU_Fzc}70!Iuq3Sk^AZMN{l` z{SAem!kTeJ{3#tnu%EpttD(mp`K~Y&#O>A^;B`%JM}vunVzU@wOyPA7Ts6Q()G!~b zTDv$l-{3iSFM!~Hym{bV5KxCrc=~@YF=u+h&^WT=vkZ|tpeKv?OsxI)+5-rmcwb9Y zRq>oC)Z9GvG6YWMr!PPB&-(Q@&irVeD)W*B!2WMaSGo_IzG0)s^&rGTz~CH1A7P$O z0@PjL`kf5DrXFo^MYG$7H{7ihT$65#v`e~xQ^ildj#Ut59>YFU3YXneLTrh(W<<#F zV9-1BAE7XVVVXU5K)A`jdJ}iDdwG6_oZ1~&o=+R9&4hBFj>RA-k;fPnAo^Q~IQO== zpX^8tQwWi_E^QzRAf{ehX6MYt%3gH2|902qLa0b%Wm-8m|L^#VvY`ZQGPzNfHT)1Y z@+%)OEndiqX)=#41FIk|129?r`w&^eAO8tLj|S@11s}}s%nq;+K5DF#2_li~H18_- zpJ*3lk;@8sb>~*TNE*3o;yQO}r&(Q7{B4QGA`F{dk9#EiuaUM$zwe6*$=fiHFa`-4 zUUGs2gEqe@fVgSVzx$!?o1fs?{IMSx+LGLbgl?~WsEXlXvY&-Yo2$>BF9kEtdw=ca ztyv*X#51xozB+9c*~Tc~gIU!EXo zmBCF%4rbn0TZisab2j78>WgfI=4E*Sfl?sCN{XT9{i~sO`6Q2p7tjD(L|qRzBr5g zSpgG`_iJ60Pv8v!@OBKe5Tfjl=vV18mApKFyn?D<6IZu+e$G# zeN_Etnw<`=Gsn2Cocmtg1~E@Lb%PHT9zDLx{|vca$n}@N7E-WIuh5aoYY>Xl*Qe0nArq-J-rTXn4clKT=xe z`3w=nEB@)9eP9u`N;poSYen}v%^n_o)o^=DJ$LKS*!vfakj;bni=;TAKo%j{3ugdP zB*SukUyF+w1g+@TP%Ki2Pvbf1 z>o?8fT_%1(vNdh1VeVv$(i(A)(E!e>75P;d38bjm&^h1$v1*2ejfp=w;eB1&szvkK zM-Xs`^_nP)c0Hn!3fT0-m!&yU1HT+trh#UR ztxql;7`{`;(5gT8IYdmd%@Zme%#OYEmlyxVr8}5k)@bo?H68B|Wl7cy{Xz8OJ7RD> z2B}r9s2N4JFAbaF_4Vhk&?Ka*mZxUhi;K%AQKpva?We?V4-bdNX(HG8L$3utURcpt z6p|WD7;7JznJj|w?CxQ35JC-@f?GC=1#B4T3Ds#BN-jU+xgF;bjR3KM$&?9JoD18{D`Mm{zPr&Xe%06keB#s%tQ?%5d4Fx zGS5ec?AW-rWZv&%;HApxiq|fxlKts}f4jlYo}=V{{8suM*F)`%fE~n}(z*~`c(YUK zP+~An%ItF(c|nKG?Z=mpqYlz~Mf1Vf5^Gq*&!i5GI<8?+GX(-VV+%T_(l6 zBDq~%2!X-cLM_N_TXHl~b#3Shl(UuJ!WJVh2iVPjXLC0A)LFTgMHSn1!Zc#fI&5?hQ??jrOwx%F# zyZL>j-MtylnieUHz2leV3 z$pDj9>Ri!s8DQ1@R6~04mkWd>bc$Ht#9p3#zSPl4J5b*lN!y=x!0R-GJFwj=dcwms z^E0-bIspx*E6N>DcrIynV<`y829NIA#n!AYq{h$x1+p?nZuTAf!fF);y$j0K*DH$N zR#5H}PI?KyWkpgZ8TjI!kv$2Dk#++~GM3ES6V7_jx>cjQ;ZC1XtcZP~7uZ}S3?tL2 z92Ltj^%F&fdj7LnFOGkOjo<}ST*z3Q@97;sA)k`H@&aex!8DvfEnCB+l{8)aCz&D5}e=Q|E@ z2Q_=Gh}Gr74;mZSo&#I-%C34Dew9RLMojAi_T6#qL3FKem98Y$8&_gKhFAu(nVvbg zv#4KpIStN!RWmR&Q*fDMK+V+6$$9tva-*gL`&z|1?IW(B2R}lTI}PN|i4@Hmt}0xy z>1fK$HX}0s>Lfw8{d^_$C4Yjpsu4{XtVMaZc;oNVH`{qg{fkhVdSm{Y!ROdvt1;pq z%5MT zwli)u-K9yTAv}8U*2RUShdV0*_yXu&GxKalhFdO{y7C_t{rNQs$)?_LpV|r~rFajS})T{22!Uljdjp-$P%eXJIM0@}cCMYlriX26{%#e$$ z|1|N_p7}%52f^E9g5UxU4E#Muzl0>hU^9KHG4)ZXx!b&{2?@z@7@Bj#)h&E1^m##z zJd!g90X1Iu@dLkiA0qZGwU8ir!&y(>uqxP%Eqn^z?Gl8^u6%w`Zk}~#*VU-2lUMcY zC;x!lNMG(74?p>NeZn`Gi=r=Oc>MQzBCS)FOy;ptcwuk5x@G=OYegg= z@%LzZN1ewY8O^>Q0NsZZutdbgxZVJtd!LT%3>SP{n69ZtYnt(wKV_&3^A7LpEWaz* zL*4`1L!<9wA0{xk-PFQ+U+emd+~519KRr~!H_(eP!-U*mP38D+6C_q`#D1A#sYr}gE$cN^W6ucY^b)hVI%h^H2FMXQnLW&6= z|40+6`olM0KRrY={v{>NDT`uOE>wJJ)erTO!(q8ETOsnXtK-{i)pU+`PF=I#@#Mnq zivIEAfl3!q?9GlZ(`uLI&wg(f)RAu2_{8|Fwo$RqKEo?jsYSYL`)%b82sPTXOO#iY zUjx%Cu?p*`QpSJ}Q&wFdndOKqwF8yjm7>*&w8i_kT!~*Qu{)>ErgUxWS(#Zp$s3&k zngsg<9cnxZ+AnFx8VjDN`y_t2HUP~?isp*Dm%Q5=I{;z;U)=M*lX5?`A}i^oZ{_aZ z4v&YgG+hmX{z@4;fwk&^SCqC3{Y>0*&)Zkk73uld+pymP;>U|NUuo9P2L+pl_Q?e# z3cKpEPv0v-HNr%G54BfLxLr2#nLN0d6d*@K^*g5DUEcHOU?yLncy@AUc9({v9@4~S zgBQ#CH~*cX_oIIJd>ya{a;i`WN=~;x*zei09qBT3!5h2fe$cXwa{4|xcZ+zx+Xg!;Pe-TO z-<}LExPRLC6AkccizA+yUO{2tGrAm}3 z{?#IQcLT&-hmh=Ex;ei29I@Q5L4T#%{ z8LSn|Nyg1v{%=?t?@$5`p&JnX@4fTcS0Rofx*m|W)&m{21DJJ~t^m%v4uh*zJstzm zeXkxvL$mH%Pa!~LWa!WP(#C~6zl5i!c+b;9F$0O{_|Ic`g1~f9a6N(XbHm|x+lw|B z!Q}VA;HWq$e0s~^XFeHx^)r*zAAjRx2hZB_mF;q0c7HB3iek2bm^pZttY{(r3J3_M zMv<0zXH-xYP#Gw0?}Z491C}61{t-SBnY!jBtg#Bk)?d8Zl;-|R_A=0)WG@P~Y+CU~ zj_&Fb^eb)1(hskg-G?XAI`RWGwUJWlSxc#ljVTvyt3M>>s=@mTEAO`b(r`N=x4pQKqUrx2 zojAXg@e63VC*HdY)05D%_8qMB85kMYKj9z@Y<6mW4F{~Y#A3aYuMUc zs_$7P3>sC~BcZy0tsUb?&jKz=he%6;**pSkIw-Z|U@JcI$J57C4>wIY$LoV6yr+Ri zYTpYvuP4jquG|uck(=(%W#6_`D>=C^>VkN_){(Y-(4oj%3PP*6bRhmAvRriJnS24R zgUetm)9?&tFS6YdxE~9J{sG>qc9$)aS?8f0{5A~<@&Vy_LcO#MvC*^5()rf{O1LT` zZxyLF+wh6ULBTw9QD);ezsGE#Y+xJwzIr;uyMlUkT(O(?($2^zfwtkGaf-*om7BOm z(b*>HuKwHDGrLpb7GFQHSfu*>I@-$_qb zlA7Q!t4SF^NBU9NMte1m&+Hj6eB{NmrTC7|6o2nrLqP)s_=bDyT-|GOv9w7WD_unn z$ry*`<=cldSNF(|eniqf9i4>(U)Hn&XU`5A3y2g4b;-H6RgmF_T5Ezp;>JN9@xK8e z9+ib{yhOxX-P(m0CxhNxDezT^tpr{AWnPQ=ocPxWj*3xzCfI&KXbT)L!8yDSp%%0K zxq&8uW{^nK*ng;JGsT1V0xIRVZ6h|vnimgdQM(CvAhM7 zc&w70c)#&weLFH^t0wSv&%vpVU0wv?=Se-nYVg1w3JV`sr}^Si8CuVqb}SHRTUlsX zWm*kY4e7|bnX_he8&$5J#Io*BZ42Lh6W|hBs&h)p{9i}^iuNx|dChNli?h<;4lo(a z63RNg9FNa49$`+}qHsjinbmJ~8yoN>jSrDipY|p0(;6Q>J7{z!CWqoPAhaP~ z`8Rl@FtKnSeD*^`N0ju2I`RGje;OyQ-`^yp=we=-OJN0yzia_%=&~xoIRdnXo-i`o zpSv`p06XM99`Uh3$-AP*M6=K{%|xL7kVTQkEFEK@_EPRw#^mB@@WL(GM=4iRS-)lO z41c%4Kb@)!0v&C?{*^q9l|LTNZ-X2nEdbMMVlkWBs-QFzzVA_HJr5JUzU5ocCLZlJ zm!Ge$BN18t{_mOSNM}(=Iv)C0wU3EO@{gSR6JI6UPa@NFxe(Sdw_-_$F1q7DVToxpgPo(R0WH(M9zes``vPyVwMbUE_1wjaYl_aS|^ za)EG?YS3@{NI`>_2!;>;m{*y;fO|@l!M(~m6NU*D9whL|mENmf`#B|QPQU=%0?J=G z1Sz9$yBWo)dG)%r(t!@*NbLWdxAqiq3TYKjGZM*Bs4Y8E%Bv=X zZK~=f8U@73O$z=Tza8Gtn zkq)p-g6fBAWt1_%bMo~GZMYifiMuYN6qF0K*Vi2U&0h2$8jdN6#hj5-A<;3z3J_Id zU;z+%kY6%fBqE;5P?Vt?|C!dM_bgl&8C8waUr0#y7K~HT`pW5h?KN0C8Glh-_1Mm! zLW{OA6?k2c?H1~r*5rDiRpO`lo)*LW)xTwk_TRjZS9H|^dQ$3T%`=s2M~Yc}egT^W z!y*kvt(3XBG9yZXC(|mnnBNbFU(+8KP#~zC7M*-Wvysnu5yH!Pa+tpJ&zI}`?PC}q z2fdn1i^Y}D+x5(p3q3v9V<`D_)l#Z>5ZINbtR8vByhtt(gzYf>AU)0 z>sbjVSqrjUXhOw6R7^UxqBDlQ9*-nixtpyk$~4P$IQNRy+Jl!lc8l-`I+QlNn!6pP z>kN){HSa>j zn6^4gw2tE_%qsbcR~0j9K%Mspu3b9`u!y7=y^rrUeuLpOJ30(sh;yj00vYvZ(kZlx z3oi7P&29Ba)S12^(Ua05)I-`UpkG5sQz4*Yfvm9BjB7jmIMt9ey$p&>L0{B*rpTObHKda~ zSIyDzE6xKR>_7ks3SL)&uNg7~oD;#9{J2;VSNw{w0$x$kPw8CkwkZ{nE?a{0LEpMX$FBMd?ka z�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 KCQU}}3I7LIh0wMxKr*ukpcjx@> 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

yh!BT5Tee-?REg;1a5DP$&CsjDy~=fq*$ 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 QBK4PN+Gw+}{<6$A9tfvL_Ay(qsCy-}Y>q3(;LL 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%0Dio) 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 WFgZpYOPu@yK#Z?i=-28xhyMrbxe6=* literal 0 HcmV?d00001 diff --git a/services/token-aggregation/scripts/generate-live-uniswap-v2-pool-catalog.ts b/services/token-aggregation/scripts/generate-live-uniswap-v2-pool-catalog.ts new file mode 100644 index 0000000..ed290b3 --- /dev/null +++ b/services/token-aggregation/scripts/generate-live-uniswap-v2-pool-catalog.ts @@ -0,0 +1,163 @@ +import fs from 'fs'; +import path from 'path'; + +type DiscoveryPayload = { + generated_at?: string; + entries?: Array<{ + chain_id: number; + network?: string; + factoryAddress?: string; + routerAddress?: string; + pairsChecked?: Array<{ + base: string; + quote: string; + poolAddress: string; + live: boolean; + health?: { + baseReserveRaw?: string; + quoteReserveRaw?: string; + baseReserveUnits?: string; + quoteReserveUnits?: string; + priceQuotePerBase?: string; + deviationBps?: string; + healthy?: boolean; + depthOk?: boolean; + parityOk?: boolean; + }; + }>; + }>; +}; + +type DeploymentStatusChain = { + name?: string; + cwTokens?: Record; + anchorAddresses?: Record; + gasMirrors?: Record; + gasQuoteAddresses?: Record; +}; + +type DeploymentStatus = { + chains?: Record; +}; + +const PRICE_USD: Record = { + USDC: 1, + USDT: 1, + cUSDC: 1, + cUSDT: 1, + cWUSDC: 1, + cWUSDT: 1, + cWAUSDT: 1, +}; + +function findRepoRoot(): string { + const candidates = [ + process.env.PROXMOX_REPO_ROOT, + process.env.PROJECT_ROOT, + path.resolve(process.cwd(), '..', '..', '..'), + path.resolve(process.cwd(), '..'), + process.cwd(), + ].filter(Boolean) as string[]; + + for (const candidate of candidates) { + if (fs.existsSync(path.join(candidate, 'reports/extraction/promod-uniswap-v2-live-pair-discovery-latest.json'))) { + return candidate; + } + } + return path.resolve(process.cwd(), '..', '..', '..'); +} + +function readJson(filePath: string): T { + return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T; +} + +function resolveTokenAddress(chain: DeploymentStatusChain, symbol: string): string | undefined { + return ( + chain.cwTokens?.[symbol] || + chain.anchorAddresses?.[symbol] || + chain.gasMirrors?.[symbol] || + chain.gasQuoteAddresses?.[symbol] + ); +} + +function parsePositiveNumber(value?: string): number { + const parsed = Number(value); + return Number.isFinite(parsed) && parsed > 0 ? parsed : 0; +} + +function main(): void { + const repoRoot = findRepoRoot(); + const discoveryPath = path.join(repoRoot, 'reports/extraction/promod-uniswap-v2-live-pair-discovery-latest.json'); + const deploymentStatusPath = path.join(repoRoot, 'cross-chain-pmm-lps/config/deployment-status.json'); + const outPath = path.join(process.cwd(), 'config/live-uniswap-v2-pool-catalog.json'); + + const discovery = readJson(discoveryPath); + const deploymentStatus = readJson(deploymentStatusPath); + const pools = []; + + for (const entry of discovery.entries ?? []) { + const chainId = Number(entry.chain_id); + const chain = deploymentStatus.chains?.[String(chainId)]; + if (!chain) continue; + + for (const pair of entry.pairsChecked ?? []) { + if (!pair.live || !pair.poolAddress?.startsWith('0x') || !pair.health) continue; + const baseAddress = resolveTokenAddress(chain, pair.base); + const quoteAddress = resolveTokenAddress(chain, pair.quote); + if (!baseAddress || !quoteAddress) continue; + + const baseReserveUnits = parsePositiveNumber(pair.health.baseReserveUnits); + const quoteReserveUnits = parsePositiveNumber(pair.health.quoteReserveUnits); + const basePriceUsd = PRICE_USD[pair.base] ?? 0; + const quotePriceUsd = PRICE_USD[pair.quote] ?? 0; + const reserve0Usd = baseReserveUnits * basePriceUsd; + const reserve1Usd = quoteReserveUnits * quotePriceUsd; + const totalLiquidityUsd = reserve0Usd + reserve1Usd; + if (totalLiquidityUsd <= 0) continue; + + pools.push({ + chainId, + chainName: entry.network ?? chain.name ?? `Chain ${chainId}`, + poolAddress: pair.poolAddress.toLowerCase(), + dex: 'uniswap_v2', + factoryAddress: entry.factoryAddress, + routerAddress: entry.routerAddress, + baseSymbol: pair.base, + quoteSymbol: pair.quote, + baseAddress: baseAddress.toLowerCase(), + quoteAddress: quoteAddress.toLowerCase(), + baseReserveRaw: pair.health.baseReserveRaw, + quoteReserveRaw: pair.health.quoteReserveRaw, + baseReserveUnits: pair.health.baseReserveUnits, + quoteReserveUnits: pair.health.quoteReserveUnits, + priceQuotePerBase: pair.health.priceQuotePerBase, + deviationBps: pair.health.deviationBps, + depthOk: pair.health.depthOk, + parityOk: pair.health.parityOk, + healthy: pair.health.healthy, + reserve0Usd, + reserve1Usd, + totalLiquidityUsd, + }); + } + } + + pools.sort((a, b) => a.chainId - b.chainId || a.poolAddress.localeCompare(b.poolAddress)); + const payload = { + schema: 'token-aggregation-live-uniswap-v2-pool-catalog/v1', + generatedAt: new Date().toISOString(), + sourceArtifacts: [ + 'reports/extraction/promod-uniswap-v2-live-pair-discovery-latest.json', + 'cross-chain-pmm-lps/config/deployment-status.json', + ], + poolCount: pools.length, + positiveLiquidityPoolCount: pools.filter((pool) => pool.totalLiquidityUsd > 0).length, + pools, + }; + + fs.mkdirSync(path.dirname(outPath), { recursive: true }); + fs.writeFileSync(outPath, `${JSON.stringify(payload, null, 2)}\n`); + console.log(outPath); +} + +main(); diff --git a/services/token-aggregation/scripts/generate-supply-proof-catalog.ts b/services/token-aggregation/scripts/generate-supply-proof-catalog.ts new file mode 100644 index 0000000..c54c299 --- /dev/null +++ b/services/token-aggregation/scripts/generate-supply-proof-catalog.ts @@ -0,0 +1,238 @@ +#!/usr/bin/env ts-node + +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; +import path from 'path'; +import { Contract, JsonRpcProvider, formatUnits } from 'ethers'; +import { CANONICAL_TOKENS, getTokenRegistryFamily } from '../src/config/canonical-tokens'; +import { getChainConfig } from '../src/config/chains'; +import { NETWORKS } from '../src/config/networks'; + +const ERC20_ABI = [ + 'function totalSupply() view returns (uint256)', + 'function decimals() view returns (uint8)', + 'function symbol() view returns (string)', + 'function name() view returns (string)', +]; + +type SupplyProof = { + schema: string; + generatedAt: string; + network: { + chainId: number; + name: string; + referenceBlock: number; + }; + token: { + address: string; + name: string; + symbol: string; + onchainName?: string; + onchainSymbol?: string; + decimals: number; + totalSupplyRaw: string; + totalSupplyUnits: string; + }; + circulatingSupplyMethodology: { + status: string; + recommendedFormula: string; + currentConservativeReportableCirculatingSupplyUnits: string; + notes: string[]; + }; + knownBalances?: unknown; + trackerSurfaces?: unknown; + [key: string]: unknown; +}; + +type SupplyProofCatalog = { + schema: string; + generatedAt: string; + proofs: SupplyProof[]; + proofFailures?: Array<{ + chainId: number; + symbol: string; + address: string; + reason: string; + }>; +}; + +function isCandidate(symbol: string, type?: string, registryFamily?: string): boolean { + return ( + /^c[A-Z0-9]/.test(symbol) && + (type === 'base' || + type === 'c' || + type === 'w' || + ['iso4217', 'monetary_unit', 'gas_native', 'commodity'].includes(String(registryFamily || ''))) + ); +} + +function catalogKey(chainId: number, address: string): string { + return `${chainId}:${address.toLowerCase()}`; +} + +function rpcUrlsForChain(chainId: number, primary?: string): string[] { + const network = NETWORKS.find((row) => row.chainIdDecimal === chainId); + return Array.from(new Set([primary, ...(network?.rpcUrls ?? [])].filter(Boolean) as string[])); +} + +function loadProofFile(proofPath: string): SupplyProof[] { + if (!existsSync(proofPath)) return []; + const parsed = JSON.parse(readFileSync(proofPath, 'utf8')) as Partial | SupplyProof; + const proofs = Array.isArray((parsed as Partial).proofs) + ? ((parsed as SupplyProofCatalog).proofs) + : [parsed as SupplyProof]; + return proofs.filter((proof) => proof?.network?.chainId && proof?.token?.address); +} + +function loadExistingCatalog(seedPaths: string[]): Map { + const proofs = new Map(); + for (const seedPath of seedPaths) { + for (const proof of loadProofFile(seedPath)) { + proofs.set(catalogKey(proof.network.chainId, proof.token.address), proof); + } + } + return proofs; +} + +function shouldPreserveExistingProof(proof: SupplyProof | undefined): boolean { + if (!proof) return false; + return ( + proof.knownBalances !== undefined || + proof.trackerSurfaces !== undefined || + proof.circulatingSupplyMethodology?.status === 'ready_for_tracker_review' + ); +} + +async function withTimeout(promise: Promise, timeoutMs: number, label: string): Promise { + let timeout: NodeJS.Timeout | undefined; + const timer = new Promise((_, reject) => { + timeout = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs); + }); + try { + return await Promise.race([promise, timer]); + } finally { + if (timeout) clearTimeout(timeout); + } +} + +async function main() { + const serviceRoot = path.resolve(__dirname, '..'); + const catalogPath = path.resolve( + process.env.TOKEN_AGGREGATION_SUPPLY_PROOF_CATALOG_JSON || + path.join(serviceRoot, 'config/supply-proof-catalog.json') + ); + const repoRoot = path.resolve(serviceRoot, '..', '..', '..'); + const timeoutMs = Number(process.env.SUPPLY_PROOF_RPC_TIMEOUT_MS || 12000); + const generatedAt = new Date().toISOString(); + const existing = loadExistingCatalog([ + catalogPath, + path.join(repoRoot, 'reports/status/mainnet-cwusdc-supply-proof-20260508.json'), + ]); + const proofs = new Map(existing); + const failures: SupplyProofCatalog['proofFailures'] = []; + + for (const spec of CANONICAL_TOKENS) { + const registryFamily = getTokenRegistryFamily(spec); + if (!isCandidate(spec.symbol, spec.type, registryFamily)) continue; + + for (const [chainIdText, rawAddress] of Object.entries(spec.addresses)) { + const chainId = Number(chainIdText); + const address = String(rawAddress || '').trim(); + if (!address.startsWith('0x')) continue; + const chain = getChainConfig(chainId); + if (!chain?.rpcUrl) { + failures.push({ chainId, symbol: spec.symbol, address, reason: 'missing_rpc_url' }); + continue; + } + + let proved = false; + const reasons: string[] = []; + for (const rpcUrl of rpcUrlsForChain(chainId, chain.rpcUrl)) { + try { + const provider = new JsonRpcProvider(rpcUrl, chainId, { staticNetwork: true }); + const contract = new Contract(address, ERC20_ABI, provider); + const [referenceBlock, totalSupplyRaw, decimals, onchainSymbol, onchainName] = await withTimeout( + Promise.all([ + provider.getBlockNumber(), + contract.totalSupply() as Promise, + contract.decimals().catch(() => spec.decimals) as Promise, + contract.symbol().catch(() => undefined) as Promise, + contract.name().catch(() => undefined) as Promise, + ]), + timeoutMs, + `${chainId}:${spec.symbol}` + ); + const decimalsNumber = Number(decimals); + const totalSupplyRawText = totalSupplyRaw.toString(); + const totalSupplyUnits = formatUnits(totalSupplyRaw, decimalsNumber); + const key = catalogKey(chainId, address); + if (!shouldPreserveExistingProof(proofs.get(key))) { + proofs.set(key, { + schema: 'token-aggregation-supply-proof/v1', + generatedAt, + network: { + chainId, + name: chain.name, + referenceBlock, + }, + token: { + address, + name: spec.name, + symbol: spec.symbol, + onchainName, + onchainSymbol, + decimals: decimalsNumber, + totalSupplyRaw: totalSupplyRawText, + totalSupplyUnits, + }, + circulatingSupplyMethodology: { + status: 'onchain_total_supply_proved_circulating_review_required', + recommendedFormula: 'circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances', + currentConservativeReportableCirculatingSupplyUnits: totalSupplyUnits, + notes: [ + 'totalSupply was read from the mapped token contract at the reference block.', + 'circulatingSupply is conservatively set to totalSupply until protocol-controlled non-circulating balances are supplied.', + 'Tracker acceptance is external and not implied by this API response.', + ], + }, + }); + } + proved = true; + break; + } catch (error) { + reasons.push(`${rpcUrl}: ${error instanceof Error ? error.message : String(error)}`); + } + } + + if (!proved) { + failures.push({ + chainId, + symbol: spec.symbol, + address, + reason: reasons.join(' | '), + }); + } + } + } + + const catalog: SupplyProofCatalog = { + schema: 'token-aggregation-supply-proof-catalog/v1', + generatedAt, + proofs: Array.from(proofs.values()).sort( + (a, b) => a.network.chainId - b.network.chainId || a.token.symbol.localeCompare(b.token.symbol) + ), + proofFailures: failures, + }; + + mkdirSync(path.dirname(catalogPath), { recursive: true }); + writeFileSync(catalogPath, `${JSON.stringify(catalog, null, 2)}\n`); + console.log(JSON.stringify({ + catalogPath, + proofs: catalog.proofs.length, + failures: failures.length, + }, null, 2)); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/services/token-aggregation/src/api/routes/bridge.ts b/services/token-aggregation/src/api/routes/bridge.ts index bfb6762..196ae69 100644 --- a/services/token-aggregation/src/api/routes/bridge.ts +++ b/services/token-aggregation/src/api/routes/bridge.ts @@ -78,6 +78,22 @@ function uniquePaths(paths: Array): string[] { return out; } +/** Non-empty built-in CCIP / trustless lane counts for /bridge/metrics (telemetry-friendly). */ +function summarizeBuiltInBridgeLanes() { + const payload = buildDefaultBridgeRoutes(); + const trustlessKeys = payload.routes.trustless ? Object.keys(payload.routes.trustless) : []; + const chain138 = payload.chain138Bridges as Record; + return { + weth9Destinations: Object.keys(payload.routes.weth9).length, + weth10Destinations: Object.keys(payload.routes.weth10).length, + trustlessDestinations: trustlessKeys.length, + chain138ConfiguredBridges: Object.keys(chain138).filter((k) => { + const v = chain138[k]; + return typeof v === 'string' && v.startsWith('0x'); + }), + }; +} + function resolveBridgeRoutesPath(): string | null { const candidates = uniquePaths([ process.env.BRIDGE_LIST_JSON_PATH, @@ -176,16 +192,35 @@ router.get('/status', (_req: Request, res: Response) => { router.get('/metrics', (_req: Request, res: Response) => { const gruTransport = buildGruTransportStatus(); + const builtIn = summarizeBuiltInBridgeLanes(); res.json({ ok: true, - lanes: [], + lanes: [ + { + kind: 'ccip-weth9', + label: 'WETH9 bridge destinations (built-in catalog)', + count: builtIn.weth9Destinations, + }, + { + kind: 'ccip-weth10', + label: 'WETH10 bridge destinations (built-in catalog)', + count: builtIn.weth10Destinations, + }, + { + kind: 'trustless', + label: 'Trustless / Lockbox destinations (env-backed)', + count: builtIn.trustlessDestinations, + }, + ], + chain138Bridges: builtIn.chain138ConfiguredBridges, gruTransport: gruTransport ? { system: gruTransport.system, summary: gruTransport.summary, } : null, - message: 'Bridge metrics include GRU Transport summary counts. Use /api/v1/report/cross-chain for aggregated data.', + message: + 'Lane counts reflect the built-in CCIP route catalog plus GRU Transport summary. Use /api/v1/bridge/routes for full JSON and /api/v1/report/cross-chain for volumes.', }); }); diff --git a/services/token-aggregation/src/api/routes/config.test.ts b/services/token-aggregation/src/api/routes/config.test.ts index 8d6b311..59944ae 100644 --- a/services/token-aggregation/src/api/routes/config.test.ts +++ b/services/token-aggregation/src/api/routes/config.test.ts @@ -139,4 +139,83 @@ describe('Config API runtime networks loader', () => { await new Promise((resolve, reject) => remoteServer.close((err) => (err ? reject(err) : resolve()))); } }); + + it('serves wallet-facing MetaMask aliases with absolute token images', async () => { + const networksRes = await fetch(`${baseUrl}/api/v1/config/networks`); + expect(networksRes.status).toBe(200); + const networksBody = (await networksRes.json()) as Record; + expect(networksBody.networks).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + chainIdDecimal: 138, + iconUrls: expect.arrayContaining([ + 'https://explorer.d-bis.org/token-icons/chain-138.png', + 'https://explorer.d-bis.org/api/v1/report/logo/chain-138', + ]), + }), + ]) + ); + + const metamaskRes = await fetch(`${baseUrl}/api/v1/config/metamask?chainId=138`); + expect(metamaskRes.status).toBe(200); + const metamaskBody = (await metamaskRes.json()) as Record; + expect(metamaskBody.addEthereumChain).toMatchObject({ + chainId: '0x8a', + chainName: 'DeFi Oracle Meta Mainnet', + }); + expect(metamaskBody.watchAssets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: 'ERC20', + options: expect.objectContaining({ + symbol: 'cUSDC', + image: expect.stringMatching(/^https:\/\/127\.0\.0\.1:\d+\/api\/v1\/report\/logo\/cUSDC\?v=20260510$/), + }), + }), + expect.objectContaining({ + type: 'ERC20', + options: expect.objectContaining({ + address: '0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03', + symbol: 'LINK', + image: expect.stringMatching(/^https:\/\/127\.0\.0\.1:\d+\/api\/v1\/report\/logo\/LINK\?v=20260510$/), + }), + }), + expect.objectContaining({ + type: 'ERC20', + options: expect.objectContaining({ + symbol: 'WETH', + image: expect.stringMatching(/^https:\/\/127\.0\.0\.1:\d+\/api\/v1\/report\/logo\/ETH\?v=20260510$/), + }), + }), + expect.objectContaining({ + type: 'ERC20', + options: expect.objectContaining({ + symbol: 'cWEMIX', + image: expect.stringMatching(/^https:\/\/127\.0\.0\.1:\d+\/api\/v1\/report\/logo\/WEMIX\?v=20260510$/), + }), + }), + ]) + ); + expect(metamaskBody.watchAssets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: 'ERC20', + options: expect.objectContaining({ + address: '0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d', + symbol: 'cUSDC', + }), + metadata: expect.objectContaining({ + catalogSymbol: 'cUSDC_V2', + familySymbol: 'cUSDC', + deploymentVersion: 'v2', + }), + }), + ]) + ); + expect( + metamaskBody.watchAssets.some( + (entry: Record) => entry.options?.symbol === 'cUSDC_V2' || entry.options?.symbol === 'cUSDT_V2' + ) + ).toBe(false); + }); }); diff --git a/services/token-aggregation/src/api/routes/config.ts b/services/token-aggregation/src/api/routes/config.ts index 8ad088a..a39f736 100644 --- a/services/token-aggregation/src/api/routes/config.ts +++ b/services/token-aggregation/src/api/routes/config.ts @@ -1,12 +1,75 @@ import { Router, Request, Response } from 'express'; import fs from 'fs'; import path from 'path'; -import { getNetworks, getConfigByChain, API_VERSION } from '../../config/networks'; +import { getNetworks, getConfigByChain, API_VERSION, type NetworkEntry } from '../../config/networks'; +import { getCanonicalTokensByChain, getLogoUriForSpec, getTokenRegistryFamily } from '../../config/canonical-tokens'; import { cacheMiddleware } from '../middleware/cache'; import { fetchRemoteJson } from '../utils/fetch-remote-json'; import { logger } from '../../utils/logger'; const router: Router = Router(); +const DEFAULT_PUBLIC_BASE_URL = 'https://explorer.d-bis.org'; +const DEFAULT_WALLET_METADATA_VERSION = '20260510'; + +function resolvePublicBaseUrl(req: Request): string { + const configured = ( + process.env.TOKEN_AGGREGATION_PUBLIC_BASE_URL ?? + process.env.PUBLIC_API_BASE_URL ?? + process.env.PUBLIC_BASE_URL ?? + '' + ).trim(); + if (configured) return configured.replace(/\/+$/, ''); + + const host = String(req.get('x-forwarded-host') || req.get('host') || '').split(',')[0].trim(); + if (host) { + let proto = String(req.get('x-forwarded-proto') || 'https').split(',')[0].trim() || 'https'; + if (proto === 'http' && !/^(localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/i.test(host)) { + proto = 'https'; + } + return `${proto}://${host}`.replace(/\/+$/, ''); + } + + return DEFAULT_PUBLIC_BASE_URL; +} + +function absolutePublicUrl(req: Request, value: string | undefined): string | undefined { + if (!value) return undefined; + if (/^https?:\/\//i.test(value)) return value; + if (!value.startsWith('/')) return value; + return `${resolvePublicBaseUrl(req)}${value}`; +} + +function appendWalletMetadataVersion(value: string | undefined): string | undefined { + if (!value) return undefined; + const version = (process.env.WALLET_METADATA_IMAGE_VERSION || DEFAULT_WALLET_METADATA_VERSION).trim(); + if (!version) return value; + const separator = value.includes('?') ? '&' : '?'; + return `${value}${separator}v=${encodeURIComponent(version)}`; +} + +function localLogoPathForSymbol(symbol: string, originalLogoUri: string): string { + if (originalLogoUri.includes('/token-lists/logos/gru/')) { + const fileName = originalLogoUri.split('/').pop()?.replace(/\.svg$/i, ''); + if (fileName) return `/api/v1/report/logo/${fileName}`; + } + if (originalLogoUri.includes('/blockchains/bitcoin/info/logo.png')) return '/api/v1/report/logo/cWBTC'; + if (originalLogoUri.includes('/ipfs/')) { + const cid = originalLogoUri.split('/').pop(); + if (cid) return `/api/v1/report/logo/ipfs-${cid}`; + } + if (symbol === 'cWUSDC') return '/api/v1/report/logo/cUSDC'; + return originalLogoUri; +} + +function resolveWalletWatchAssetSymbol(spec: { symbol: string; familySymbol?: string; deploymentVersion?: string }): string { + // MetaMask validates wallet_watchAsset.symbol against ERC-20 symbol(). + // Staged V2 Chain 138 deployments currently keep the family symbol on-chain + // (for example cUSDC), while the catalog symbol distinguishes the row + // (for example cUSDC_V2). Keep the catalog identity in metadata and send the + // contract-facing symbol in options.symbol so EIP-747 succeeds. + if (spec.deploymentVersion && spec.familySymbol) return spec.familySymbol; + return spec.symbol; +} type RuntimeNetworksPayload = { version?: string | { major?: number; minor?: number; patch?: number }; @@ -124,16 +187,77 @@ async function resolveNetworksPayload(): Promise { }; } +async function sendNetworks(_req: Request, res: Response): Promise { + res.set('Cache-Control', 'public, max-age=0, must-revalidate'); + const payload = await resolveNetworksPayload(); + res.json(payload); +} + /** * GET /api/v1/networks * Full EIP-3085 chain params for wallet_addEthereumChain (Chain 138, 1, 651940). * If NETWORKS_JSON_URL is set (e.g. GitHub raw URL), fetches and returns that JSON; otherwise uses built-in networks. */ -router.get('/networks', cacheMiddleware(5 * 60 * 1000), async (req: Request, res: Response) => { +router.get(['/networks', '/config/networks', '/metamask/networks'], cacheMiddleware(5 * 60 * 1000), async (req: Request, res: Response) => { + try { + await sendNetworks(req, res); + } catch (error) { + res.status(500).json({ error: 'Internal server error' }); + } +}); + +/** + * GET /api/v1/config/metamask + * Wallet-facing aliases for Chain 138 add-chain params and watchAsset token entries. + */ +router.get(['/config/metamask', '/metamask'], cacheMiddleware(5 * 60 * 1000), async (req: Request, res: Response) => { try { res.set('Cache-Control', 'public, max-age=0, must-revalidate'); + const chainId = parseInt(String(req.query.chainId ?? '138'), 10) || 138; const payload = await resolveNetworksPayload(); - res.json(payload); + const networks = payload.networks as NetworkEntry[]; + const network = networks.find((entry) => Number(entry.chainIdDecimal) === chainId); + if (!network) { + res.status(404).json({ error: 'Chain not found', chainId }); + return; + } + + const watchAssets = getCanonicalTokensByChain(chainId) + .map((spec) => { + const address = spec.addresses[chainId]; + if (!address) return null; + const originalLogoURI = getLogoUriForSpec(spec); + return { + type: 'ERC20', + options: { + address, + symbol: resolveWalletWatchAssetSymbol(spec), + decimals: spec.decimals, + image: appendWalletMetadataVersion(absolutePublicUrl(req, localLogoPathForSymbol(spec.symbol, originalLogoURI))), + }, + metadata: { + name: spec.name, + catalogSymbol: spec.symbol, + registryFamily: getTokenRegistryFamily(spec), + familySymbol: spec.familySymbol, + deploymentVersion: spec.deploymentVersion, + deploymentStatus: spec.deploymentStatus, + }, + }; + }) + .filter(Boolean); + + res.json({ + source: payload.source, + version: payload.version, + chainId, + addEthereumChain: network, + watchAssets, + caveats: [ + 'MetaMask custom-token prices are controlled by MetaMask and its upstream asset/price providers; this endpoint supplies wallet metadata, logo URLs, and token-add payloads but cannot force MetaMask to render fiat prices.', + 'After metadata changes, remove and re-add the custom network/token in MetaMask or use the companion UI to call wallet_addEthereumChain and wallet_watchAsset again.', + ], + }); } catch (error) { res.status(500).json({ error: 'Internal server error' }); } diff --git a/services/token-aggregation/src/api/routes/report.test.ts b/services/token-aggregation/src/api/routes/report.test.ts index ef70e3c..a74fd21 100644 --- a/services/token-aggregation/src/api/routes/report.test.ts +++ b/services/token-aggregation/src/api/routes/report.test.ts @@ -91,6 +91,24 @@ describe('Report API', () => { const body = (await res.json()) as Record; expect(body.chainId).toBe(651940); }); + + it('enriches Mainnet cWUSDC with supply proof fields for CMC reports', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/cmc?chainId=1`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + const cwusdc = body.tokens.find((token: Record) => token.symbol === 'cWUSDC'); + expect(cwusdc).toMatchObject({ + contract_address: '0x2de5f116bfce3d0f922d9c8351e0c5fc24b9284a', + total_supply: 10451316981.309788, + total_supply_raw: '10451316981309788', + circulating_supply: 10451316981.309788, + market_cap: 10451316981.309788, + supply_proof_provenance: expect.objectContaining({ + status: 'ready_for_tracker_review', + }), + }); + expect(cwusdc.tracker_caveats).toEqual(expect.arrayContaining([expect.stringContaining('on-chain supply proof')])); + }); }); describe('GET /api/v1/report/coingecko', () => { @@ -104,6 +122,62 @@ describe('Report API', () => { expect(body).toHaveProperty('tokens'); expect(Array.isArray(body.tokens)).toBe(true); }); + + it('enriches Mainnet cWUSDC with supply proof, circulating supply, and market cap', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/coingecko?chainId=1`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + const cwusdc = body.tokens.find((token: Record) => token.symbol === 'cWUSDC'); + expect(cwusdc).toMatchObject({ + contract_address: '0x2de5f116bfce3d0f922d9c8351e0c5fc24b9284a', + total_supply: 10451316981.309788, + total_supply_raw: '10451316981309788', + circulating_supply: 10451316981.309788, + circulating_supply_formula: 'circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances', + supply_proof_provenance: expect.objectContaining({ + schema: 'mainnet-cwusdc-supply-proof/v1', + referenceBlock: 25047586, + }), + market_data: expect.objectContaining({ + current_price: { usd: 1 }, + market_cap: 10451316981.309788, + }), + }); + expect(cwusdc.tracker_caveats).toEqual(expect.arrayContaining([expect.stringContaining('No public tracker')])); + }); + + it('surfaces GRU v2 deployment-status pools in tracker-facing token reports', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/coingecko?chainId=1`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + const cwusdc = body.tokens.find((token: Record) => token.symbol === 'cWUSDC'); + expect(cwusdc.liquidity_pools).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + pool_address: '0x69776fc607e9eda8042e320e7e43f54d06c68f0e', + source: 'gru-v2-deployment-status', + status: 'live', + role: 'defense', + }), + ]) + ); + }); + + it('surfaces explicit supply-proof gaps for Mainnet GRU assets without proof artifacts', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/coingecko?chainId=1`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + const cwusdt = body.tokens.find((token: Record) => token.symbol === 'cWUSDT'); + expect(cwusdt).toMatchObject({ + contract_address: '0xaf5017d0163ecb99d9b5d94e3b4d7b09af44d8ae', + supply_proof_provenance: { + source: 'missing-supply-proof', + status: 'proof_required', + }, + }); + expect(cwusdt).not.toHaveProperty('total_supply'); + expect(cwusdt.tracker_caveats).toEqual(expect.arrayContaining([expect.stringContaining('tracker-grade supply proof')])); + }); }); describe('GET /api/v1/report/all', () => { @@ -149,6 +223,72 @@ describe('Report API', () => { }), }); }); + + it('includes Mainnet cWUSDC supply proof enrichment in unified reports', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/all?chainId=1`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + const cwusdc = body.tokens?.['1']?.find((token: Record) => token.symbol === 'cWUSDC'); + expect(cwusdc).toMatchObject({ + totalSupply: '10451316981.309788', + totalSupplyRaw: '10451316981309788', + circulatingSupply: '10451316981.309788', + circulatingSupplyFormula: 'circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances', + market: expect.objectContaining({ + priceUsd: 1, + marketCapUsd: 10451316981.309788, + }), + supplyProofProvenance: expect.objectContaining({ + schema: 'mainnet-cwusdc-supply-proof/v1', + referenceBlock: 25047586, + }), + }); + }); + + it('distinguishes proof-gated Mainnet cW assets from deterministic placeholder bindings', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/all?chainId=1`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + const proofGated = body.tokens?.['1']?.find((entry: Record) => entry.symbol === 'cWUSDT'); + expect(proofGated).toMatchObject({ + supplyProofProvenance: { + source: 'missing-supply-proof', + status: 'proof_required', + }, + }); + expect(proofGated.totalSupply).toBeUndefined(); + expect(proofGated.trackerCaveats).toEqual(expect.arrayContaining([expect.stringContaining('proof artifact')])); + + const placeholderSymbols = ['cWBTC', 'cWETH']; + for (const symbol of placeholderSymbols) { + const token = body.tokens?.['1']?.find((entry: Record) => entry.symbol === symbol); + expect(token).toMatchObject({ + supplyProofProvenance: { + source: 'deterministic-placeholder-address', + status: 'non_reportable_until_erc20_deployed', + }, + }); + expect(token.totalSupply).toBeUndefined(); + expect(token.trackerCaveats).toEqual(expect.arrayContaining([expect.stringContaining('deterministic placeholder')])); + } + }); + + it('marks proofless base GRU c assets as proof gated instead of leaving silent supply fields', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/all?chainId=138`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + const cusdc = body.tokens?.['138']?.find((entry: Record) => entry.symbol === 'cUSDC'); + expect(cusdc).toMatchObject({ + type: 'base', + registryFamily: 'iso4217', + supplyProofProvenance: { + source: 'missing-supply-proof', + status: 'proof_required', + }, + }); + expect(cusdc.totalSupply).toBeUndefined(); + expect(cusdc.trackerCaveats).toEqual(expect.arrayContaining([expect.stringContaining('tracker-grade supply proof')])); + }); }); describe('GET /api/v1/report/gas-registry', () => { @@ -185,6 +325,63 @@ describe('Report API', () => { }); }); + describe('GET /api/v1/report/adoption-readiness', () => { + it('summarizes proved, proof-gated, pool-indexed, and scoring gates', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/adoption-readiness`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + expect(body.scope).toBe('gru-c-and-cw-assets'); + expect(body.counts).toMatchObject({ + candidates: expect.any(Number), + reportableCandidates: expect.any(Number), + nonReportablePlaceholder: expect.any(Number), + proved: expect.any(Number), + proofRequired: expect.any(Number), + silent: 0, + liquidityMissing: expect.any(Number), + liquidityMissingWithPools: expect.any(Number), + liquidityMissingWithoutPools: expect.any(Number), + gruV2PoolsWithStatus: expect.any(Number), + }); + expect(body.institutional.score).toEqual(expect.any(Number)); + expect(body.cryptoListing.score).toEqual(expect.any(Number)); + expect(Array.isArray(body.blockerInventory.proofRequiredByChain)).toBe(true); + expect(Array.isArray(body.blockerInventory.liquidityMissingByChain)).toBe(true); + expect(Array.isArray(body.blockerInventory.liquidityMissingWithPoolsByChain)).toBe(true); + expect(Array.isArray(body.blockerInventory.liquidityMissingWithoutPoolsByChain)).toBe(true); + expect(Array.isArray(body.blockerInventory.liquidityMissingDetails)).toBe(true); + expect(Array.isArray(body.blockerInventory.externalOfficialQuoteLiquidityByChain)).toBe(true); + expect(Array.isArray(body.blockerInventory.nonReportablePlaceholderByChain)).toBe(true); + expect(Array.isArray(body.blockerInventory.gruV2PoolsMissingStatus)).toBe(true); + expect(Array.isArray(body.blockerInventory.notes)).toBe(true); + }); + + it('does not treat external official USDC/USDT mirrors as GRU liquidity blockers', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/adoption-readiness`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + expect(body.counts.externalOfficialQuoteLiquidity).toBeGreaterThan(0); + expect(body.blockerInventory.externalOfficialQuoteLiquidityByChain).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + chainId: 1, + symbols: expect.arrayContaining(['cUSDC', 'cUSDT']), + }), + expect.objectContaining({ + chainId: 56, + symbols: expect.arrayContaining(['cUSDC', 'cUSDT']), + }), + ]) + ); + expect(body.blockerInventory.liquidityMissingDetails).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ chainId: 1, symbol: 'cUSDT' }), + expect.objectContaining({ chainId: 56, symbol: 'cUSDC' }), + ]) + ); + }); + }); + describe('GET /api/v1/report/token-list', () => { it('surfaces both V1 and V2 Chain 138 canonical GRU deployments explicitly', async () => { const res = await fetch(`${baseUrl}/api/v1/report/token-list?chainId=138`); @@ -379,6 +576,17 @@ describe('Report API', () => { ]) ); }); + + it('uses packaged DBIS-level local logo assets while preserving original logo references', async () => { + const res = await fetch(`${baseUrl}/api/v1/report/token-list?chainId=1`); + expect(res.status).toBe(200); + const body = (await res.json()) as Record; + const cwusdc = body.tokens.find((token: Record) => token.symbol === 'cWUSDC'); + expect(cwusdc).toMatchObject({ + logoURI: expect.stringMatching(/^https:\/\/127\.0\.0\.1:\d+\/api\/v1\/report\/logo\/cUSDC$/), + originalLogoURI: expect.stringContaining('/token-lists/logos/gru/cUSDC.svg'), + }); + }); }); describe('GET /api/v1/report/cw-registry', () => { @@ -488,6 +696,8 @@ describe('Report API', () => { expect((body.pools as Array<{ poolAddress: string }>)[0]).toMatchObject({ poolAddress: '0x1111111111111111111111111111111111111111', section: 'pmmPools', + status: 'routing_enabled', + statusReason: expect.stringContaining('public routing is enabled'), }); } finally { await import('fs/promises').then((fs) => fs.unlink(tempPath).catch(() => undefined)); diff --git a/services/token-aggregation/src/api/routes/report.ts b/services/token-aggregation/src/api/routes/report.ts index 4f06c95..1e3b9f7 100644 --- a/services/token-aggregation/src/api/routes/report.ts +++ b/services/token-aggregation/src/api/routes/report.ts @@ -4,6 +4,8 @@ */ import { Router, Request, Response } from 'express'; +import { existsSync, readFileSync } from 'fs'; +import path from 'path'; import { TokenRepository } from '../../database/repositories/token-repo'; import { MarketDataRepository } from '../../database/repositories/market-data-repo'; import { PoolRepository } from '../../database/repositories/pool-repo'; @@ -19,21 +21,543 @@ import { cacheMiddleware } from '../middleware/cache'; import { fetchRemoteJson } from '../utils/fetch-remote-json'; import { buildCrossChainReport } from '../../indexer/cross-chain-indexer'; import { logger } from '../../utils/logger'; -import { filterPoolsForExposure, getActiveTransportPairs, getGruTransportMetadata } from '../../config/gru-transport'; +import { + filterPoolsForExposure, + getActiveTransportPairs, + getGruTransportMetadata, + type GruTransportGasAssetFamily, + type GruTransportPair, +} from '../../config/gru-transport'; import { buildCwRegistryChains, buildGasRegistryChains, loadDeploymentStatusFile, + type DeploymentStatusFile, type CwRegistryChain, } from '../../config/deployment-status'; import { getGruV2DeploymentPoolRows } from '../../config/gru-v2-deployment-pools'; import { getCanonicalPriceSnapshotGeneratedAt, getCanonicalPriceUsd } from '../../services/canonical-price-oracle'; +import { pmmVaultReserveFromChain, resolvePmmQuoteRpcUrl } from '../../services/pmm-onchain-quote'; const router: Router = Router(); const tokenRepo = new TokenRepository(); const marketDataRepo = new MarketDataRepository(); const poolRepo = new PoolRepository(); +const MAINNET_CWUSDC_ADDRESS = '0x2de5f116bfce3d0f922d9c8351e0c5fc24b9284a'; +const DEFAULT_SUPPLY_CATALOG_RELATIVE_PATH = 'config/supply-proof-catalog.json'; +const DEFAULT_LIVE_UNISWAP_V2_POOL_CATALOG_RELATIVE_PATH = 'config/live-uniswap-v2-pool-catalog.json'; +const DEFAULT_PUBLIC_REPORT_BASE_URL = 'https://explorer.d-bis.org'; +const DBIS_CHAIN_138_LOGO_PATH = '/api/v1/report/logo/chain-138'; +const CWUSDC_SUPPLY_PROOF_FALLBACK = { + schema: 'mainnet-cwusdc-supply-proof/v1', + generatedAt: '2026-05-08T03:16:54Z', + network: { + chainId: 1, + name: 'Ethereum Mainnet', + referenceBlock: 25047586, + }, + token: { + address: MAINNET_CWUSDC_ADDRESS, + name: 'Wrapped cUSDC', + symbol: 'cWUSDC', + decimals: 6, + totalSupplyRaw: '10451316981309788', + totalSupplyUnits: '10451316981.309788', + }, + circulatingSupplyMethodology: { + status: 'ready_for_tracker_review', + recommendedFormula: 'circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances', + currentConservativeReportableCirculatingSupplyUnits: '10451316981.309788', + notes: [ + 'No public tracker has accepted a circulating-supply value for this contract yet.', + 'If a tracker requires exclusion of operator, treasury, bridge, or protocol-controlled balances, use the knownBalances section plus any additional signed treasury inventory supplied at submission time.', + 'The value above is an on-chain supply proof, not a third-party listing approval.', + ], + }, +}; + +type SupplyProofSnapshot = typeof CWUSDC_SUPPLY_PROOF_FALLBACK & { + _sourcePath?: string; + _source?: string; +}; + +type SupplyProofEnrichment = { + totalSupply?: string; + totalSupplyRaw?: string; + circulatingSupply?: string; + circulatingSupplyFormula?: string; + marketCapUsd?: number; + supplyProofProvenance: { + source: string; + path?: string; + schema?: string; + generatedAt?: string; + referenceBlock?: number; + status?: string; + }; + trackerCaveats: string[]; +}; + +type ReportPoolEntry = { + poolAddress: string; + dex: string; + token0: string; + token1: string; + token0Symbol?: string; + token1Symbol?: string; + tvl: number; + volume24h: number; + source?: string; + status?: string; + statusReason?: string; + role?: string; + section?: string; + publicRoutingEnabled?: boolean; + reserveSource?: string; + reserveUpdatedAt?: string; + reserve0Raw?: string; + reserve1Raw?: string; +}; + +type LiveUniswapV2PoolCatalogRow = { + chainId: number; + poolAddress: string; + dex?: string; + baseSymbol: string; + quoteSymbol: string; + baseAddress: string; + quoteAddress: string; + totalLiquidityUsd: number; + reserve0Usd?: number; + reserve1Usd?: number; + depthOk?: boolean; + parityOk?: boolean; + healthy?: boolean; + deviationBps?: string; +}; + +type LiveUniswapV2PoolCatalog = { + schema?: string; + generatedAt?: string; + pools?: LiveUniswapV2PoolCatalogRow[]; +}; + +function resolveRepoRoot(): string { + const candidates = [ + process.env.PROXMOX_REPO_ROOT, + process.env.PROJECT_ROOT, + path.resolve(process.cwd(), '..', '..', '..'), + path.resolve(process.cwd(), '..'), + process.cwd(), + ].filter(Boolean) as string[]; + + for (const candidate of candidates) { + if ( + existsSync(path.join(candidate, DEFAULT_SUPPLY_CATALOG_RELATIVE_PATH)) || + existsSync(path.join(candidate, DEFAULT_LIVE_UNISWAP_V2_POOL_CATALOG_RELATIVE_PATH)) || + existsSync(path.join(candidate, 'reports/status/mainnet-cwusdc-supply-proof-20260508.json')) + ) { + return candidate; + } + } + return process.cwd(); +} + +function loadLiveUniswapV2PoolCatalog(): LiveUniswapV2PoolCatalogRow[] { + const configuredCatalog = process.env.TOKEN_AGGREGATION_LIVE_UNISWAP_V2_POOL_CATALOG_JSON?.trim(); + const repoRoot = resolveRepoRoot(); + const candidates = [ + configuredCatalog, + path.join(repoRoot, DEFAULT_LIVE_UNISWAP_V2_POOL_CATALOG_RELATIVE_PATH), + ].filter(Boolean) as string[]; + + for (const candidate of candidates) { + if (!existsSync(candidate)) continue; + try { + const parsed = JSON.parse(readFileSync(candidate, 'utf8')) as LiveUniswapV2PoolCatalog; + return (parsed.pools ?? []).filter( + (pool) => + Number.isFinite(pool.chainId) && + pool.poolAddress?.startsWith('0x') && + pool.baseAddress?.startsWith('0x') && + pool.quoteAddress?.startsWith('0x') + ); + } catch (error) { + logger.warn('Unable to parse live Uniswap V2 pool catalog; skipping file', { candidate, error }); + } + } + + return []; +} + +function normalizeSupplyProofKey(chainId: number, address: string): string { + return `${chainId}:${address.toLowerCase()}`; +} + +function loadSupplyProofFile(proofPath: string, source: string): SupplyProofSnapshot[] { + if (!proofPath || !existsSync(proofPath)) return []; + + try { + const parsed = JSON.parse(readFileSync(proofPath, 'utf8')) as { proofs?: SupplyProofSnapshot[] } | SupplyProofSnapshot; + const proofs: SupplyProofSnapshot[] = Array.isArray((parsed as { proofs?: SupplyProofSnapshot[] })?.proofs) + ? ((parsed as { proofs: SupplyProofSnapshot[] }).proofs) + : [parsed as SupplyProofSnapshot]; + return proofs + .filter((proof) => proof?.network?.chainId && proof?.token?.address) + .map((proof) => ({ + ...proof, + _source: source, + _sourcePath: proofPath, + })); + } catch (error) { + logger.warn('Unable to parse supply proof file; skipping file', { proofPath, error }); + return []; + } +} + +function loadSupplyProofCatalog(): Map { + const configuredCatalog = process.env.TOKEN_AGGREGATION_SUPPLY_PROOF_CATALOG_JSON?.trim(); + const configuredSingleProof = process.env.CWUSDC_SUPPLY_PROOF_JSON?.trim(); + const repoRoot = resolveRepoRoot(); + const candidates = [ + configuredCatalog ? { path: configuredCatalog, source: 'configured-supply-proof-catalog' } : null, + { path: path.join(repoRoot, DEFAULT_SUPPLY_CATALOG_RELATIVE_PATH), source: 'repo-supply-proof-catalog' }, + configuredSingleProof ? { path: configuredSingleProof, source: 'configured-supply-proof-file' } : null, + { path: path.join(repoRoot, 'reports/status/mainnet-cwusdc-supply-proof-20260508.json'), source: 'repo-supply-proof-file' }, + ].filter(Boolean) as Array<{ path: string; source: string }>; + + const byToken = new Map(); + for (const candidate of candidates) { + for (const proof of loadSupplyProofFile(candidate.path, candidate.source)) { + const key = normalizeSupplyProofKey(Number(proof.network.chainId), String(proof.token.address)); + if (!byToken.has(key)) { + byToken.set(key, proof); + } + } + } + + if (!byToken.has(normalizeSupplyProofKey(1, MAINNET_CWUSDC_ADDRESS))) { + byToken.set(normalizeSupplyProofKey(1, MAINNET_CWUSDC_ADDRESS), { + ...CWUSDC_SUPPLY_PROOF_FALLBACK, + _source: 'embedded-fallback-snapshot', + }); + } + + return byToken; +} + +function isGruSupplyTrackedCandidate(symbol: string, type?: string, registryFamily?: string): boolean { + return ( + /^c[A-Z0-9]/.test(symbol) && + (type === 'base' || + type === 'c' || + type === 'w' || + ['iso4217', 'monetary_unit', 'gas_native', 'commodity'].includes(String(registryFamily || ''))) + ); +} + +const EXTERNAL_OFFICIAL_QUOTE_ASSETS = new Set([ + '1:cUSDC:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + '1:cUSDT:0xdac17f958d2ee523a2206206994597c13d831ec7', + '10:cUSDC:0x0b2c639c533813f4aa9d7837caf62653d097ff85', + '10:cUSDT:0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', + '25:cUSDC:0xc21223249ca28397b4b6541dffaecc539bff0c59', + '25:cUSDT:0x66e428c3f67a68878562e79a0234c1f83c208770', + '56:cUSDC:0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', + '56:cUSDT:0x55d398326f99059ff775485246999027b3197955', + '100:cUSDC:0xddafbb505ad214d7b80b1f830fccc89b60fb7a83', + '100:cUSDT:0x4ecaba5870353805a9f068101a40e0f32ed605c6', + '137:cUSDC:0x3c499c542cef5e3811e1192ce70d8cc03d5c3359', + '137:cUSDT:0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + '8453:cUSDC:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', + '8453:cUSDT:0xfde4c96c8593536e31f229ea8f37b2ada2699bb2', + '42161:cUSDC:0xaf88d065e77c8cc2239327c5edb3a432268e5831', + '42161:cUSDT:0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + '42220:cUSDC:0xceba9300f2b948710d2653dd7b07f33a8b32118c', + '42220:cUSDT:0x48065fbbe25f71c9282ddf5e1cd6d6a887483d5e', + '43114:cUSDC:0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', + '43114:cUSDT:0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7', + '1111:cUSDC:0xe3f5a90f9cb311505cd691a46596599aa1a0ad7d', + '1111:cUSDT:0xa649325aa7c5093d12d6f98eb4378deae68ce23f', + '651940:cUSDC:0xa95eed79f84e6a0151eaeb9d441f9ffd50e8e881', + '651940:cUSDT:0x015b1897ed5279930bc2be46f661894d219292a6', +]); + +function hasExternalOfficialQuoteLiquidity(token: { chainId: number; symbol: string; address: string }): boolean { + return EXTERNAL_OFFICIAL_QUOTE_ASSETS.has(`${token.chainId}:${token.symbol}:${token.address.toLowerCase()}`); +} + +function isDeterministicPlaceholderAddress(address: string): boolean { + const normalized = address.toLowerCase(); + return /^0x[a-f0-9]{4}0{24,}[a-f0-9]{1,8}$/.test(normalized); +} + +function buildSupplyProofEnrichment( + chainId: number, + address: string, + symbol: string, + type: string | undefined, + registryFamily: string | undefined, + priceUsd?: number +): SupplyProofEnrichment | undefined { + const proof = loadSupplyProofCatalog().get(normalizeSupplyProofKey(chainId, address)); + + if (!proof) { + if (!isGruSupplyTrackedCandidate(symbol, type, registryFamily)) return undefined; + if (isDeterministicPlaceholderAddress(address)) { + return { + supplyProofProvenance: { + source: 'deterministic-placeholder-address', + status: 'non_reportable_until_erc20_deployed', + }, + trackerCaveats: [ + 'This token binding is a deterministic placeholder address and does not currently behave as an ERC-20 contract.', + 'Do not submit totalSupply, circulatingSupply, marketCapUsd, or liquidity claims for this asset until a deployed ERC-20 binding replaces the placeholder.', + 'The placeholder is kept visible for registry and routing roadmap traceability only.', + ], + }; + } + return { + supplyProofProvenance: { + source: 'missing-supply-proof', + status: 'proof_required', + }, + trackerCaveats: [ + 'No token-specific on-chain supply proof artifact is currently attached to this report response.', + 'Do not submit totalSupply, circulatingSupply, or marketCapUsd for this asset until a current proof artifact is generated and linked.', + 'Registry and pool visibility are not the same as tracker-grade supply proof.', + ], + }; + } + + const totalSupply = String(proof.token?.totalSupplyUnits ?? ''); + const totalSupplyRaw = String(proof.token?.totalSupplyRaw ?? ''); + const circulatingSupply = String( + proof.circulatingSupplyMethodology?.currentConservativeReportableCirculatingSupplyUnits ?? totalSupply + ); + const parsedCirculatingSupply = Number(circulatingSupply); + const marketCapUsd = + priceUsd !== undefined && Number.isFinite(parsedCirculatingSupply) ? parsedCirculatingSupply * priceUsd : undefined; + + return { + totalSupply, + totalSupplyRaw, + circulatingSupply, + circulatingSupplyFormula: String( + proof.circulatingSupplyMethodology?.recommendedFormula ?? + 'circulatingSupply = totalSupply - protocolControlledNonCirculatingBalances' + ), + marketCapUsd, + supplyProofProvenance: { + source: proof._source ?? 'repo-supply-proof-file', + path: proof._sourcePath, + schema: proof.schema, + generatedAt: proof.generatedAt, + referenceBlock: proof.network?.referenceBlock, + status: proof.circulatingSupplyMethodology?.status, + }, + trackerCaveats: proof.circulatingSupplyMethodology?.notes ?? [ + 'Tracker acceptance is external and not implied by this API response.', + ], + }; +} + +function resolveGruV2ReserveRpcUrl(chainId: number): string { + const configured = resolvePmmQuoteRpcUrl(); + if (chainId === 138 && process.env.NODE_ENV !== 'test') return configured || 'http://192.168.11.211:8545'; + if (chainId === 56 && process.env.NODE_ENV !== 'test') { + return process.env.BSC_RPC_URL || process.env.BSC_MAINNET_RPC || process.env.RPC_URL_56 || 'https://bsc-rpc.publicnode.com'; + } + if (chainId === 43114 && process.env.NODE_ENV !== 'test') { + return ( + process.env.AVALANCHE_RPC_URL || + process.env.AVALANCHE_MAINNET_RPC || + process.env.RPC_URL_43114 || + 'https://avalanche-c-chain-rpc.publicnode.com' + ); + } + if (chainId === 1111 && process.env.NODE_ENV !== 'test') { + return process.env.WEMIX_MAINNET_RPC || process.env.WEMIX_RPC || process.env.RPC_URL_1111 || 'https://api.wemix.com'; + } + return ''; +} + +function decimalFromRawForReport(raw: bigint, decimals: number): number { + const scale = 10 ** decimals; + return Number(raw) / scale; +} + +function fallbackPoolDecimals(symbol?: string): number { + const normalized = String(symbol || '').toUpperCase(); + if (normalized === 'WETH' || normalized === 'ETH') return 18; + return 6; +} + +function fallbackPoolUsdPrice(symbol?: string): number { + const normalized = String(symbol || '').toUpperCase(); + if (normalized.includes('XAU')) return Number(process.env.TOKEN_AGGREGATION_XAU_USD || '0') || 0; + if (normalized === 'WETH' || normalized === 'ETH') return Number(process.env.TOKEN_AGGREGATION_ETH_USD || '0') || 0; + return 1; +} + +async function enrichGruV2FallbackPoolWithReserves(chainId: number, pool: ReportPoolEntry): Promise { + const rpcUrl = resolveGruV2ReserveRpcUrl(chainId); + if (!rpcUrl) return pool; + + const reserves = await pmmVaultReserveFromChain({ rpcUrl, poolAddress: pool.poolAddress }); + if (!reserves) return pool; + + const baseUnits = decimalFromRawForReport(reserves.baseReserveRaw, fallbackPoolDecimals(pool.token0Symbol)); + const quoteUnits = decimalFromRawForReport(reserves.quoteReserveRaw, fallbackPoolDecimals(pool.token1Symbol)); + const reserveUsd = + baseUnits * fallbackPoolUsdPrice(pool.token0Symbol) + quoteUnits * fallbackPoolUsdPrice(pool.token1Symbol); + + if (!Number.isFinite(reserveUsd) || reserveUsd <= 0) { + return { + ...pool, + reserveSource: 'onchain-gru-v2-pmm-getVaultReserve', + reserveUpdatedAt: new Date().toISOString(), + reserve0Raw: reserves.baseReserveRaw.toString(), + reserve1Raw: reserves.quoteReserveRaw.toString(), + }; + } + + return { + ...pool, + tvl: reserveUsd, + status: pool.status ?? 'reserve_visible', + statusReason: + pool.statusReason ?? + 'Pool is present in deployment-status and has positive on-chain reserves via getVaultReserve().', + reserveSource: 'onchain-gru-v2-pmm-getVaultReserve', + reserveUpdatedAt: new Date().toISOString(), + reserve0Raw: reserves.baseReserveRaw.toString(), + reserve1Raw: reserves.quoteReserveRaw.toString(), + }; +} + +async function buildGruV2FallbackPoolsForToken( + chainId: number, + tokenAddress: string, + existingPools: ReportPoolEntry[] +): Promise { + const token = tokenAddress.toLowerCase(); + const existing = new Set(existingPools.map((pool) => pool.poolAddress.toLowerCase())); + const pools = getGruV2DeploymentPoolRows() + .filter((pool) => pool.chainId === chainId) + .filter((pool) => pool.baseAddress.toLowerCase() === token || pool.quoteAddress.toLowerCase() === token) + .filter((pool) => !existing.has(pool.poolAddress.toLowerCase())) + .map((pool) => ({ + poolAddress: pool.poolAddress, + dex: pool.venue ?? 'gru_v2_pmm', + token0: pool.baseAddress, + token1: pool.quoteAddress, + token0Symbol: pool.baseSymbol, + token1Symbol: pool.quoteSymbol, + tvl: 0, + volume24h: 0, + source: 'gru-v2-deployment-status', + status: pool.status, + statusReason: pool.statusReason, + role: pool.role, + section: pool.section, + publicRoutingEnabled: pool.publicRoutingEnabled, + })); + + return Promise.all(pools.map((pool) => enrichGruV2FallbackPoolWithReserves(chainId, pool))); +} + +function buildLiveUniswapV2FallbackPoolsForToken( + chainId: number, + tokenAddress: string, + existingPools: ReportPoolEntry[] +): ReportPoolEntry[] { + const token = tokenAddress.toLowerCase(); + const existing = new Set(existingPools.map((pool) => pool.poolAddress.toLowerCase())); + return loadLiveUniswapV2PoolCatalog() + .filter((pool) => pool.chainId === chainId) + .filter((pool) => pool.baseAddress.toLowerCase() === token || pool.quoteAddress.toLowerCase() === token) + .filter((pool) => !existing.has(pool.poolAddress.toLowerCase())) + .map((pool) => ({ + poolAddress: pool.poolAddress, + dex: pool.dex ?? 'uniswap_v2', + token0: pool.baseAddress, + token1: pool.quoteAddress, + token0Symbol: pool.baseSymbol, + token1Symbol: pool.quoteSymbol, + tvl: Number(pool.totalLiquidityUsd ?? 0), + volume24h: 0, + source: 'live-uniswap-v2-pair-discovery', + status: pool.healthy ? 'indexed_live_healthy' : 'indexed_live_needs_repair', + statusReason: pool.healthy + ? 'Live Uniswap V2 pair discovered with on-chain reserves, depth, and parity checks passing.' + : `Live Uniswap V2 pair discovered; depthOk=${pool.depthOk === true}, parityOk=${pool.parityOk === true}, deviationBps=${pool.deviationBps ?? 'unknown'}.`, + role: 'public_indexable_liquidity', + publicRoutingEnabled: pool.healthy === true, + })); +} + +function resolveLocalLogoUri(remoteLogoUri: string, symbol: string): string | undefined { + if (remoteLogoUri.startsWith('/api/v1/report/logo/')) { + return remoteLogoUri; + } + if (remoteLogoUri.includes('/token-lists/logos/gru/')) { + const fileName = remoteLogoUri.split('/').pop()?.replace(/\.svg$/i, ''); + return fileName ? `/api/v1/report/logo/${fileName}` : undefined; + } + if (remoteLogoUri.includes('/blockchains/bitcoin/info/logo.png')) { + return '/api/v1/report/logo/cWBTC'; + } + if (remoteLogoUri.includes('/ipfs/')) { + const cid = remoteLogoUri.split('/').pop(); + return cid ? `/api/v1/report/logo/ipfs-${cid}` : undefined; + } + if (symbol === 'cWUSDC') { + return '/api/v1/report/logo/cUSDC'; + } + return undefined; +} + +function resolvePublicBaseUrl(req: Request): string { + const configured = ( + process.env.TOKEN_AGGREGATION_PUBLIC_BASE_URL ?? + process.env.PUBLIC_API_BASE_URL ?? + process.env.PUBLIC_BASE_URL ?? + '' + ).trim(); + if (configured) return configured.replace(/\/+$/, ''); + + const host = String(req.get('x-forwarded-host') || req.get('host') || '').split(',')[0].trim(); + if (host) { + let proto = String(req.get('x-forwarded-proto') || 'https').split(',')[0].trim() || 'https'; + if (proto === 'http' && !/^(localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/i.test(host)) { + proto = 'https'; + } + return `${proto}://${host}`.replace(/\/+$/, ''); + } + + return DEFAULT_PUBLIC_REPORT_BASE_URL; +} + +function absolutePublicUrl(req: Request, value: string | undefined): string | undefined { + if (!value) return undefined; + if (/^https?:\/\//i.test(value)) return value; + if (!value.startsWith('/')) return value; + return `${resolvePublicBaseUrl(req)}${value}`; +} + +function absoluteLogoUri(req: Request, remoteLogoUri: string, symbol: string): string { + const localLogoURI = resolveLocalLogoUri(remoteLogoUri, symbol); + return absolutePublicUrl(req, localLogoURI) ?? remoteLogoUri; +} + +function absoluteReportLogoUri(remoteLogoUri: string, symbol: string): string { + const localLogoURI = resolveLocalLogoUri(remoteLogoUri, symbol); + if (localLogoURI?.startsWith('/')) return `${DEFAULT_PUBLIC_REPORT_BASE_URL}${localLogoURI}`; + return localLogoURI ?? remoteLogoUri; +} + /** Build token entries with DB market/pool data for a chain */ async function buildTokenReport(chainId: number) { const canonical = getCanonicalTokensByChain(chainId); @@ -51,6 +575,8 @@ async function buildTokenReport(chainId: number) { deploymentStatus?: string; preferredForX402?: boolean; liquiditySourceSymbol?: string; + logoURI?: string; + originalLogoURI?: string; market?: { priceUsd?: number; volume24h: number; @@ -60,14 +586,13 @@ async function buildTokenReport(chainId: number) { liquidityUsd: number; lastUpdated: string; }; - pools: Array<{ - poolAddress: string; - dex: string; - token0: string; - token1: string; - tvl: number; - volume24h: number; - }>; + totalSupply?: string; + totalSupplyRaw?: string; + circulatingSupply?: string; + circulatingSupplyFormula?: string; + supplyProofProvenance?: SupplyProofEnrichment['supplyProofProvenance']; + trackerCaveats?: string[]; + pools: ReportPoolEntry[]; fromDb: boolean; }> = []; @@ -98,6 +623,58 @@ async function buildTokenReport(chainId: number) { const fallbackPriceUsd = getCanonicalPriceUsd(chainId, address); + const market = marketData + ? { + priceUsd: marketData.priceUsd ?? fallbackPriceUsd, + volume24h: marketData.volume24h, + volume7d: marketData.volume7d, + volume30d: marketData.volume30d, + marketCapUsd: marketData.marketCapUsd, + liquidityUsd: marketData.liquidityUsd, + lastUpdated: marketData.lastUpdated?.toISOString() ?? '', + } + : fallbackPriceUsd !== undefined + ? { + priceUsd: fallbackPriceUsd, + volume24h: 0, + volume7d: 0, + volume30d: 0, + liquidityUsd: 0, + lastUpdated: `${getCanonicalPriceSnapshotGeneratedAt()}T00:00:00.000Z`, + } + : undefined; + const registryFamily = getTokenRegistryFamily(spec); + const originalLogoURI = getLogoUriForSpec(spec); + const logoURI = absoluteReportLogoUri(originalLogoURI, spec.symbol); + const supplyProof = buildSupplyProofEnrichment(chainId, address, spec.symbol, spec.type, registryFamily, market?.priceUsd); + if (supplyProof?.marketCapUsd !== undefined && market) { + market.marketCapUsd = supplyProof.marketCapUsd; + } + + const dbPoolEntries: ReportPoolEntry[] = resolvedPools.map((p) => ({ + poolAddress: p.poolAddress, + dex: p.dex, + token0: p.token0.address, + token1: p.token1.address, + token0Symbol: p.token0.symbol, + token1Symbol: p.token1.symbol, + tvl: p.tvl, + volume24h: p.volume24h, + source: 'indexed-db', + status: 'indexed', + statusReason: 'Pool is present in the token-aggregation indexed pool repository.', + })); + const liveUniswapV2PoolEntries = buildLiveUniswapV2FallbackPoolsForToken(chainId, address, dbPoolEntries); + const gruV2FallbackPoolEntries = await buildGruV2FallbackPoolsForToken(chainId, address, [ + ...dbPoolEntries, + ...liveUniswapV2PoolEntries, + ]); + const reportPools = [ + ...dbPoolEntries, + ...liveUniswapV2PoolEntries, + ...gruV2FallbackPoolEntries, + ]; + out.push({ chainId, address: address.toLowerCase(), @@ -106,42 +683,22 @@ async function buildTokenReport(chainId: number) { type: spec.type, decimals: spec.decimals, currencyCode: spec.currencyCode, - registryFamily: getTokenRegistryFamily(spec), + registryFamily, familySymbol: spec.familySymbol, deploymentVersion: spec.deploymentVersion, deploymentStatus: spec.deploymentStatus, preferredForX402: spec.preferredForX402, liquiditySourceSymbol: spec.liquiditySourceSymbol, - market: marketData - ? { - priceUsd: marketData.priceUsd ?? fallbackPriceUsd, - volume24h: marketData.volume24h, - volume7d: marketData.volume7d, - volume30d: marketData.volume30d, - marketCapUsd: marketData.marketCapUsd, - liquidityUsd: marketData.liquidityUsd, - lastUpdated: marketData.lastUpdated?.toISOString() ?? '', - } - : fallbackPriceUsd !== undefined - ? { - priceUsd: fallbackPriceUsd, - volume24h: 0, - volume7d: 0, - volume30d: 0, - liquidityUsd: 0, - lastUpdated: `${getCanonicalPriceSnapshotGeneratedAt()}T00:00:00.000Z`, - } - : undefined, - pools: resolvedPools.map((p) => ({ - poolAddress: p.poolAddress, - dex: p.dex, - token0: p.token0.address, - token1: p.token1.address, - token0Symbol: p.token0.symbol, - token1Symbol: p.token1.symbol, - tvl: p.tvl, - volume24h: p.volume24h, - })), + logoURI, + originalLogoURI, + market, + totalSupply: supplyProof?.totalSupply, + totalSupplyRaw: supplyProof?.totalSupplyRaw, + circulatingSupply: supplyProof?.circulatingSupply, + circulatingSupplyFormula: supplyProof?.circulatingSupplyFormula, + supplyProofProvenance: supplyProof?.supplyProofProvenance, + trackerCaveats: supplyProof?.trackerCaveats, + pools: reportPools, fromDb: !!dbToken, }); } @@ -167,15 +724,42 @@ function describeToken(spec: { currencyCode?: string; registryFamily?: string }) function buildGruTransportOverview() { const gruTransportMetadata = getGruTransportMetadata(); - if (!gruTransportMetadata) return undefined; + const deploymentStatus = loadDeploymentStatusFile()?.data; + + if (!gruTransportMetadata && !deploymentStatus) return undefined; + + const activeTransportPairs = getActiveTransportPairs(); + const fallbackGasAssetFamilies = deploymentStatus ? buildGasAssetFamiliesFromDeploymentStatus(deploymentStatus) : []; + const fallbackRuntimePairs = deploymentStatus ? buildGasRuntimePairsFromDeploymentStatus(deploymentStatus) : []; + const gasAssetFamilies = gruTransportMetadata?.gasAssetFamilies ?? fallbackGasAssetFamilies; + const gasRedeemGroups = gruTransportMetadata?.gasRedeemGroups ?? []; + const gasProtocolExposure = gruTransportMetadata?.gasProtocolExposure ?? []; + const runtimePairs = activeTransportPairs.length > 0 ? activeTransportPairs : fallbackRuntimePairs; return { - system: gruTransportMetadata.system, - summary: gruTransportMetadata.counts, - gasAssetFamilies: gruTransportMetadata.gasAssetFamilies ?? [], - gasRedeemGroups: gruTransportMetadata.gasRedeemGroups ?? [], - gasProtocolExposure: gruTransportMetadata.gasProtocolExposure ?? [], - activeTransportPairs: getActiveTransportPairs().map((pair) => ({ + system: gruTransportMetadata?.system ?? { + name: 'GRU Monetary Transport Layer', + shortName: 'GRU Transport', + canonicalChainId: 138, + canonicalChainName: 'DeFi Oracle Meta Chain 138', + transportClass: 'deployment-status-fallback', + }, + summary: gruTransportMetadata?.counts ?? { + enabledCanonicalTokens: 0, + enabledDestinationChains: new Set(runtimePairs.map((pair) => pair.destinationChainId)).size, + approvedBridgePeers: 0, + transportPairs: runtimePairs.length, + gasAssetFamilies: gasAssetFamilies.length, + gasRedeemGroups: gasRedeemGroups.length, + gasProtocolExposure: gasProtocolExposure.length, + gasTransportPairs: runtimePairs.length, + runtimeReadyTransportPairs: runtimePairs.filter((pair) => pair.runtimeReady === true).length, + publicPools: 0, + }, + gasAssetFamilies, + gasRedeemGroups, + gasProtocolExposure, + activeTransportPairs: runtimePairs.map((pair) => ({ key: pair.key, canonicalSymbol: pair.canonicalSymbol, mirroredSymbol: pair.mirroredSymbol, @@ -200,6 +784,173 @@ function buildGruTransportOverview() { }; } +function gasFamilyDefaults(familyKey: string, mirroredSymbol: string) { + const byFamily: Record = { + eth_mainnet: { + canonicalSymbol138: 'cETH', + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: 'eth_mainnet', + }, + eth_l2: { + canonicalSymbol138: 'cETHL2', + assetClass: 'gas_native', + backingMode: 'hybrid_cap', + redeemPolicy: 'same_family_only', + laneGroup: 'eth_l2', + }, + bnb: { + canonicalSymbol138: 'cBNB', + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: 'bnb', + }, + pol: { + canonicalSymbol138: 'cPOL', + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: 'pol', + }, + avax: { + canonicalSymbol138: 'cAVAX', + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: 'avax', + }, + cro: { + canonicalSymbol138: 'cCRO', + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: 'cro', + }, + xdai: { + canonicalSymbol138: 'cXDAI', + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: 'xdai', + }, + celo: { + canonicalSymbol138: 'cCELO', + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: 'celo', + }, + wemix: { + canonicalSymbol138: 'cWEMIX', + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: 'wemix', + }, + }; + + return byFamily[familyKey] ?? { + canonicalSymbol138: mirroredSymbol.replace(/^cW/, 'c'), + assetClass: 'gas_native', + backingMode: 'strict_escrow', + redeemPolicy: 'same_family_only', + laneGroup: familyKey, + }; +} + +function buildGasAssetFamiliesFromDeploymentStatus(data: DeploymentStatusFile): GruTransportGasAssetFamily[] { + const byFamily = new Map(); + + for (const [chainIdText, chain] of Object.entries(data.chains ?? {})) { + const chainId = Number(chainIdText); + for (const pool of chain.gasPmmPools ?? []) { + const familyKey = typeof pool.familyKey === 'string' ? pool.familyKey : ''; + const mirroredSymbol = typeof pool.base === 'string' ? pool.base : ''; + if (!familyKey || !mirroredSymbol) continue; + const defaults = gasFamilyDefaults(familyKey, mirroredSymbol); + const existing = byFamily.get(familyKey) ?? { + familyKey, + active: true, + status: 'deployment_status_fallback', + canonicalSymbol138: defaults.canonicalSymbol138, + mirroredSymbol, + assetClass: defaults.assetClass, + originChains: [], + laneGroup: defaults.laneGroup, + backingMode: defaults.backingMode, + redeemPolicy: defaults.redeemPolicy, + wrappedNativeQuoteSymbol: 'WETH', + stableQuoteSymbol: 'USDC', + referenceVenue: 'deployment-status', + }; + if (!existing.originChains.includes(chainId)) { + existing.originChains.push(chainId); + } + if (typeof pool.quote === 'string' && ['WETH', 'WBNB', 'WPOL', 'WAVAX', 'WCRO', 'WXDAI', 'CELO', 'WEMIX'].includes(pool.quote)) { + existing.wrappedNativeQuoteSymbol = pool.quote; + } + if (typeof pool.quote === 'string' && ['USDC', 'USDT', 'DAI'].includes(pool.quote)) { + existing.stableQuoteSymbol = pool.quote; + } + byFamily.set(familyKey, existing); + } + } + + return Array.from(byFamily.values()).sort((a, b) => a.familyKey.localeCompare(b.familyKey)); +} + +function buildGasRuntimePairsFromDeploymentStatus(data: DeploymentStatusFile): GruTransportPair[] { + const familiesByKey = new Map(buildGasAssetFamiliesFromDeploymentStatus(data).map((family) => [family.familyKey, family])); + const pairs: GruTransportPair[] = []; + + for (const [chainIdText, chain] of Object.entries(data.chains ?? {})) { + const destinationChainId = Number(chainIdText); + const seen = new Set(); + for (const pool of chain.gasPmmPools ?? []) { + const familyKey = typeof pool.familyKey === 'string' ? pool.familyKey : ''; + const mirroredSymbol = typeof pool.base === 'string' ? pool.base : ''; + if (!familyKey || !mirroredSymbol || seen.has(familyKey)) continue; + seen.add(familyKey); + const family = familiesByKey.get(familyKey); + const canonicalSymbol = family?.canonicalSymbol138 ?? gasFamilyDefaults(familyKey, mirroredSymbol).canonicalSymbol138; + pairs.push({ + key: `138-${destinationChainId}-${canonicalSymbol}-${mirroredSymbol}`, + canonicalChainId: 138, + destinationChainId, + destinationChainName: chain.name ?? `Chain ${chainIdText}`, + active: true, + status: 'deployment_status_fallback', + canonicalSymbol, + mirroredSymbol, + mappingKey: `${canonicalSymbol}:${destinationChainId}`, + peerKey: `chain-${destinationChainId}`, + assetClass: 'gas_native', + familyKey, + laneGroup: family?.laneGroup, + backingMode: family?.backingMode, + redeemPolicy: family?.redeemPolicy, + wrappedNativeQuoteSymbol: family?.wrappedNativeQuoteSymbol, + stableQuoteSymbol: family?.stableQuoteSymbol, + mirrorDeploymentAddress: chain.gasMirrors?.[mirroredSymbol], + mirrorDeployed: !!chain.gasMirrors?.[mirroredSymbol], + canonicalEnabled: true, + destinationEnabled: true, + bridgeAvailable: chain.bridgeAvailable === true, + bridgePeerConfigured: chain.bridgeAvailable === true, + runtimeBridgeReady: chain.bridgeAvailable === true, + runtimeReady: chain.bridgeAvailable === true && !!chain.gasMirrors?.[mirroredSymbol], + eligible: true, + runtimeMissingRequirements: chain.bridgeAvailable === true ? [] : ['bridgeAvailable is not true in deployment-status'], + eligibilityBlockers: [], + }); + } + } + + return pairs.sort((a, b) => a.destinationChainId - b.destinationChainId || a.familyKey!.localeCompare(b.familyKey!)); +} + function buildCanonicalCwFallback(chainIdFilter?: number | null): CwRegistryChain[] { const grouped = new Map(); @@ -230,6 +981,42 @@ function buildCanonicalCwFallback(chainIdFilter?: number | null): CwRegistryChai .sort((a, b) => a.chainId - b.chainId); } +/** GET /report/assets/* — packaged report assets such as controlled token logos. */ +router.get(/^\/assets\/(.+)$/, (req: Request, res: Response) => { + const assetPath = String(req.params[0] ?? ''); + const publicRoot = path.resolve(__dirname, '../../../public'); + const resolved = path.resolve(publicRoot, assetPath); + + if (!resolved.startsWith(publicRoot) || !existsSync(resolved)) { + res.status(404).json({ error: 'Asset not found' }); + return; + } + + res.set('Cache-Control', 'public, max-age=86400, immutable'); + res.sendFile(resolved); +}); + +/** GET /report/logo/:symbol — extensionless public logo route for proxies that block static file extensions. */ +router.get('/logo/:symbol', (req: Request, res: Response) => { + const rawSymbol = String(req.params.symbol ?? '').trim(); + const publicRoot = path.resolve(__dirname, '../../../public/token-logos'); + const gruSymbol = rawSymbol.replace(/^cW(?=USD|EUR|GBP|AUD|JPY|CHF|CAD|XAU)/, 'c'); + const candidates = [ + rawSymbol === 'cWBTC' ? path.join(publicRoot, 'trustwallet/btc-logo.png') : '', + rawSymbol.startsWith('ipfs-') ? path.join(publicRoot, 'ipfs', rawSymbol.replace(/^ipfs-/, '')) : '', + path.join(publicRoot, 'gru', `${gruSymbol}.svg`), + ].filter(Boolean); + + const resolved = candidates.find((candidate) => existsSync(candidate)); + if (!resolved) { + res.status(404).json({ error: 'Logo not found' }); + return; + } + + res.set('Cache-Control', 'public, max-age=86400, immutable'); + res.sendFile(resolved); +}); + /** GET /report/cross-chain — cross-chain pools, bridge volume, atomic swaps (Chain 138, ALL Mainnet) */ router.get( '/cross-chain', @@ -338,7 +1125,15 @@ router.get( name: t.name, asset_platform_id: chainId === 138 ? 'defi-oracle-meta' : chainId === 651940 ? 'all-mainnet' : `chain-${chainId}`, decimals: t.decimals, + logo_uri: t.logoURI, + original_logo_uri: t.originalLogoURI, description: describeToken(t), + total_supply: t.totalSupply ? Number(t.totalSupply) : undefined, + total_supply_raw: t.totalSupplyRaw, + circulating_supply: t.circulatingSupply ? Number(t.circulatingSupply) : undefined, + circulating_supply_formula: t.circulatingSupplyFormula, + supply_proof_provenance: t.supplyProofProvenance, + tracker_caveats: t.trackerCaveats, market_data: t.market ? { current_price: { usd: t.market.priceUsd }, @@ -353,6 +1148,14 @@ router.get( dex_id: p.dex, tvl_usd: p.tvl, volume_24h_usd: p.volume24h, + source: p.source, + status: p.status, + status_reason: p.statusReason, + role: p.role, + section: p.section, + public_routing_enabled: p.publicRoutingEnabled, + base_symbol: p.token0Symbol, + quote_symbol: p.token1Symbol, })), })); @@ -395,6 +1198,14 @@ router.get( symbol: t.symbol, name: t.name, decimals: t.decimals, + logo_url: t.logoURI, + original_logo_url: t.originalLogoURI, + total_supply: t.totalSupply ? Number(t.totalSupply) : undefined, + total_supply_raw: t.totalSupplyRaw, + circulating_supply: t.circulatingSupply ? Number(t.circulatingSupply) : undefined, + circulating_supply_formula: t.circulatingSupplyFormula, + supply_proof_provenance: t.supplyProofProvenance, + tracker_caveats: t.trackerCaveats, volume_24h: t.market?.volume24h, market_cap: t.market?.marketCapUsd, liquidity_usd: t.market?.liquidityUsd ?? t.pools.reduce((s, p) => s + p.tvl, 0), @@ -405,6 +1216,12 @@ router.get( quote: p.token0 === t.address ? p.token1 : p.token0, liquidity_usd: p.tvl, volume_24h_usd: p.volume24h, + source: p.source, + status: p.status, + status_reason: p.statusReason, + role: p.role, + section: p.section, + public_routing_enabled: p.publicRoutingEnabled, })), })); @@ -456,12 +1273,16 @@ router.get( if (!isNaN(chainIdFilter as number)) { tokens = tokens.filter((t) => t.chainId === chainIdFilter); } + const normalizedTokens = tokens.map((token) => ({ + ...token, + logoURI: absolutePublicUrl(req, typeof token.logoURI === 'string' ? token.logoURI : undefined) ?? token.logoURI, + })); return res.json({ name: data.name ?? 'Token List', version: data.version ?? '1.0.0', timestamp: data.timestamp ?? new Date().toISOString(), - logoURI: data.logoURI, - tokens, + logoURI: absolutePublicUrl(req, data.logoURI) ?? data.logoURI, + tokens: normalizedTokens, }); } catch (err) { logger.error('TOKEN_LIST_JSON_URL fetch failed, using built-in token list:', err); @@ -481,6 +1302,7 @@ router.get( decimals: number; type: string; logoURI: string; + originalLogoURI?: string; registryFamily?: string; familySymbol?: string; deploymentVersion?: string; @@ -493,6 +1315,7 @@ router.get( for (const spec of specs) { const address = spec.addresses[chainId]; if (address) { + const originalLogoURI = getLogoUriForSpec(spec); list.push({ chainId, address: address.toLowerCase(), @@ -500,7 +1323,8 @@ router.get( name: spec.name, decimals: spec.decimals, type: spec.type, - logoURI: getLogoUriForSpec(spec), + logoURI: absoluteLogoUri(req, originalLogoURI, spec.symbol), + originalLogoURI, registryFamily: getTokenRegistryFamily(spec), familySymbol: spec.familySymbol, deploymentVersion: spec.deploymentVersion, @@ -515,7 +1339,7 @@ router.get( name: 'GRU Canonical Token List', version: '1.0.0', timestamp: new Date().toISOString(), - logoURI: 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png', + logoURI: absolutePublicUrl(req, DBIS_CHAIN_138_LOGO_PATH), tokens: list, }); } catch (error) { @@ -586,6 +1410,150 @@ router.get('/gru-v2-pmm-pools', async (req: Request, res: Response) => { } }); +/** GET /report/adoption-readiness — summary gates for institutional and tracker/listing readiness. */ +router.get('/adoption-readiness', async (_req: Request, res: Response) => { + try { + const chainIds = getSupportedChainIds(); + const tokensByChain: Record>> = {}; + for (const chainId of chainIds) { + tokensByChain[chainId] = await buildTokenReport(chainId); + } + + const allTokens = Object.values(tokensByChain).flat(); + const candidates = allTokens.filter((token) => + isGruSupplyTrackedCandidate(token.symbol, token.type, token.registryFamily) + ); + const nonReportablePlaceholder = candidates.filter( + (token) => token.supplyProofProvenance?.source === 'deterministic-placeholder-address' + ); + const reportableCandidates = candidates.filter( + (token) => token.supplyProofProvenance?.source !== 'deterministic-placeholder-address' + ); + const proved = reportableCandidates.filter((token) => token.supplyProofProvenance && token.supplyProofProvenance.source !== 'missing-supply-proof'); + const proofRequired = reportableCandidates.filter((token) => token.supplyProofProvenance?.source === 'missing-supply-proof'); + const silent = reportableCandidates.filter((token) => !token.supplyProofProvenance); + const externalOfficialQuoteLiquidity = reportableCandidates.filter(hasExternalOfficialQuoteLiquidity); + const liquidityPositive = reportableCandidates.filter( + (token) => (token.market?.liquidityUsd ?? 0) > 0 || token.pools.some((pool) => pool.tvl > 0) || hasExternalOfficialQuoteLiquidity(token) + ); + const poolIndexed = reportableCandidates.filter((token) => token.pools.length > 0); + const liquidityMissing = reportableCandidates.filter( + (token) => (token.market?.liquidityUsd ?? 0) <= 0 && !token.pools.some((pool) => pool.tvl > 0) && !hasExternalOfficialQuoteLiquidity(token) + ); + const liquidityMissingWithPools = liquidityMissing.filter((token) => token.pools.length > 0); + const liquidityMissingWithoutPools = liquidityMissing.filter((token) => token.pools.length === 0); + const gruPools = getGruV2DeploymentPoolRows(); + const groupTokensByChain = (tokens: typeof candidates) => + tokens + .reduce>((groups, token) => { + let group = groups.find((row) => row.chainId === token.chainId); + if (!group) { + group = { chainId: token.chainId, count: 0, symbols: [] }; + groups.push(group); + } + group.count += 1; + group.symbols.push(token.symbol); + return groups; + }, []) + .map((group) => ({ + ...group, + symbols: Array.from(new Set(group.symbols)).sort(), + })) + .sort((a, b) => a.chainId - b.chainId); + + res.set('Cache-Control', 'public, max-age=0, must-revalidate'); + res.json({ + generatedAt: new Date().toISOString(), + scope: 'gru-c-and-cw-assets', + counts: { + candidates: candidates.length, + reportableCandidates: reportableCandidates.length, + nonReportablePlaceholder: nonReportablePlaceholder.length, + proved: proved.length, + proofRequired: proofRequired.length, + silent: silent.length, + poolIndexed: poolIndexed.length, + liquidityPositive: liquidityPositive.length, + liquidityMissing: liquidityMissing.length, + liquidityMissingWithPools: liquidityMissingWithPools.length, + liquidityMissingWithoutPools: liquidityMissingWithoutPools.length, + externalOfficialQuoteLiquidity: externalOfficialQuoteLiquidity.length, + gruV2Pools: gruPools.length, + gruV2PoolsWithStatus: gruPools.filter((pool) => !!pool.status).length, + }, + institutional: { + score: Math.round( + 100 * + ((silent.length === 0 ? 0.25 : 0) + + (proved.length / Math.max(reportableCandidates.length, 1)) * 0.35 + + (poolIndexed.length / Math.max(reportableCandidates.length, 1)) * 0.2 + + (gruPools.length > 0 && gruPools.every((pool) => !!pool.status) ? 0.2 : 0)) + ), + blockers: [ + proofRequired.length > 0 ? `${proofRequired.length} assets still require supply-proof artifacts.` : null, + silent.length > 0 ? `${silent.length} assets have no proof state.` : null, + gruPools.some((pool) => !pool.status) ? 'One or more GRU v2 pools lacks lifecycle status.' : null, + ].filter(Boolean), + }, + cryptoListing: { + score: Math.round( + 100 * + ((proved.length / Math.max(reportableCandidates.length, 1)) * 0.45 + + (liquidityPositive.length / Math.max(reportableCandidates.length, 1)) * 0.35 + + (poolIndexed.length / Math.max(reportableCandidates.length, 1)) * 0.2) + ), + blockers: [ + proofRequired.length > 0 ? 'Most c*/cW* assets are proof-gated for supply and market-cap claims.' : null, + liquidityPositive.length < reportableCandidates.length ? 'Not every reportable c*/cW* asset has positive indexed liquidity in the report API.' : null, + ].filter(Boolean), + }, + blockerInventory: { + proofRequiredByChain: groupTokensByChain(proofRequired), + liquidityMissingByChain: groupTokensByChain(liquidityMissing), + liquidityMissingWithPoolsByChain: groupTokensByChain(liquidityMissingWithPools), + liquidityMissingWithoutPoolsByChain: groupTokensByChain(liquidityMissingWithoutPools), + liquidityMissingDetails: liquidityMissing + .map((token) => ({ + chainId: token.chainId, + symbol: token.symbol, + address: token.address, + poolCount: token.pools.length, + zeroTvlPoolCount: token.pools.filter((pool) => pool.tvl <= 0).length, + marketLiquidityUsd: token.market?.liquidityUsd ?? 0, + category: token.pools.length > 0 ? 'configured_or_indexed_pools_zero_tvl' : 'no_visible_pool_binding', + })) + .sort((a, b) => a.chainId - b.chainId || a.symbol.localeCompare(b.symbol)), + externalOfficialQuoteLiquidityByChain: groupTokensByChain(externalOfficialQuoteLiquidity), + nonReportablePlaceholderByChain: groupTokensByChain(nonReportablePlaceholder), + gruV2PoolsMissingStatus: gruPools + .filter((pool) => !pool.status) + .map((pool) => ({ + chainId: pool.chainId, + poolAddress: pool.poolAddress, + baseSymbol: pool.baseSymbol, + quoteSymbol: pool.quoteSymbol, + })), + notes: [ + 'proof_required means the report intentionally withholds totalSupply, circulatingSupply, and marketCap claims for that asset.', + 'nonReportablePlaceholder means the configured address is intentionally visible for roadmap traceability but is not a deployed ERC-20 proof surface.', + 'liquidityMissing means no positive indexed liquidity is currently visible through the report API for that asset.', + 'External official quote mirrors (public-chain USDC/USDT and ALL AUSDC/AUSDT) are not GRU pool blockers when their canonical token binding is proved; their public venue liquidity is maintained by the issuer/external market and should not be confused with repo-native cW*/Chain 138 liquidity.', + 'A configured pool or registry entry is not the same thing as tracker-grade supply proof or live positive liquidity.', + ], + }, + proofRequiredSample: proofRequired.slice(0, 20).map((token) => ({ + chainId: token.chainId, + symbol: token.symbol, + address: token.address, + status: token.supplyProofProvenance?.status, + })), + }); + } catch (error) { + logger.error('Error building report/adoption-readiness:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}); + /** GET /report/gas-registry — live gas-family rollout registry from deployment-status.json plus GRU transport metadata. */ router.get('/gas-registry', async (req: Request, res: Response) => { try { @@ -593,7 +1561,9 @@ router.get('/gas-registry', async (req: Request, res: Response) => { const chainIdFilter = chainIdParam ? parseInt(chainIdParam, 10) : null; const fileBackedRegistry = loadDeploymentStatusFile(); const gruTransport = buildGruTransportOverview(); - const runtimeGasPairs = getActiveTransportPairs() + const loaderRuntimePairs = getActiveTransportPairs(); + const fallbackRuntimePairs = fileBackedRegistry ? buildGasRuntimePairsFromDeploymentStatus(fileBackedRegistry.data) : []; + const runtimeGasPairs = (loaderRuntimePairs.length > 0 ? loaderRuntimePairs : fallbackRuntimePairs) .filter((pair) => pair.assetClass === 'gas_native') .map((pair) => ({ key: pair.key, diff --git a/services/token-aggregation/src/api/server.ts b/services/token-aggregation/src/api/server.ts index b9f3aa2..ee70ff3 100644 --- a/services/token-aggregation/src/api/server.ts +++ b/services/token-aggregation/src/api/server.ts @@ -1,4 +1,5 @@ import express, { Express, Request, Response, NextFunction } from 'express'; +import { Server } from 'http'; import path from 'path'; import { readFileSync, existsSync } from 'fs'; import cors from 'cors'; @@ -48,6 +49,7 @@ export class ApiServer { private indexerEnabled: boolean; private indexer: MultiChainIndexer | null; private omnlPoller: OmnlEventPoller | null; + private server: Server | null; private resolveTrustProxySetting(): boolean | number | string { const raw = (process.env.EXPRESS_TRUST_PROXY ?? process.env.TRUST_PROXY ?? '1').trim(); @@ -65,6 +67,7 @@ export class ApiServer { this.indexerEnabled = this.resolveFeatureFlag('ENABLE_INDEXER', true); this.indexer = this.indexerEnabled ? new MultiChainIndexer() : null; this.omnlPoller = this.resolveFeatureFlag('ENABLE_OMNL_EVENT_POLLER', false) ? new OmnlEventPoller() : null; + this.server = null; this.setupMiddleware(); this.setupRoutes(); @@ -106,6 +109,14 @@ export class ApiServer { }); next(); }); + + const publicPath = path.join(__dirname, '../../public'); + if (existsSync(publicPath)) { + this.app.use('/static', express.static(publicPath, { + immutable: true, + maxAge: '1d', + })); + } } private setupRoutes(): void { @@ -151,6 +162,39 @@ export class ApiServer { res.type('html').send(readFileSync(dashboardPath, 'utf8')); }); + // Public API catalog (register before routers so GET /api/v1 is not swallowed by middleware-only mounts) + const sendApiV1Catalog = (_req: Request, res: Response) => { + res.json({ + service: 'token-aggregation', + version: '1.0.0', + note: 'Prefix paths with your public API origin (e.g. https://explorer.d-bis.org).', + paths: { + catalog: '/api/v1', + health: '/health', + chains: '/api/v1/chains', + networks: '/api/v1/networks', + config: '/api/v1/config', + tokens: '/api/v1/tokens', + tokenDetail: '/api/v1/tokens/{address}', + quote: '/api/v1/quote', + bridgeRoutes: '/api/v1/bridge/routes', + bridgeStatus: '/api/v1/bridge/status', + bridgeMetrics: '/api/v1/bridge/metrics', + bridgePreflight: '/api/v1/bridge/preflight', + tokenMappingPairs: '/api/v1/token-mapping/pairs', + tokenMappingResolve: '/api/v1/token-mapping/resolve', + reportTokenList: '/api/v1/report/token-list', + routesTree: '/api/v1/routes/tree', + plannerProvidersCapabilities: '/api/v2/providers/capabilities', + plannerRoutesPlan: '/api/v2/routes/plan', + plannerIntentsPlan: '/api/v2/intents/plan', + plannerInternalExecutionPlan: '/api/v2/routes/internal-execution-plan', + }, + }); + }; + this.app.get('/api/v1', sendApiV1Catalog); + this.app.get('/api/v1/', sendApiV1Catalog); + // API routes this.app.use('/api/v1', tokenRoutes); this.app.use('/api/v1', configRoutes); @@ -206,21 +250,25 @@ export class ApiServer { async start(): Promise { try { + // Start server + this.server = this.app.listen(this.port, () => { + logger.info(`Token Aggregation Service listening on port ${this.port}`); + logger.info(`Health check: http://localhost:${this.port}/health`); + logger.info(`API: http://localhost:${this.port}/api/v1`); + }); + if (this.indexer) { - await this.indexer.initialize(); - await this.indexer.startAll(); + this.indexer + .initialize() + .then(() => this.indexer?.startAll()) + .catch((error) => { + logger.error('Token aggregation indexer failed after API startup:', error); + }); } else { logger.info('Token aggregation indexer disabled by ENABLE_INDEXER flag'); } this.omnlPoller?.start(); - - // Start server - this.app.listen(this.port, () => { - logger.info(`Token Aggregation Service listening on port ${this.port}`); - logger.info(`Health check: http://localhost:${this.port}/health`); - logger.info(`API: http://localhost:${this.port}/api/v1`); - }); } catch (error) { logger.error('Failed to start server:', error); process.exit(1); @@ -230,6 +278,18 @@ export class ApiServer { async stop(): Promise { this.omnlPoller?.stop(); this.indexer?.stopAll(); + if (this.server) { + await new Promise((resolve, reject) => { + this.server?.close((error) => { + if (error) { + reject(error); + return; + } + resolve(); + }); + }); + this.server = null; + } logger.info('Server stopped'); } } diff --git a/services/token-aggregation/src/config/canonical-tokens.test.ts b/services/token-aggregation/src/config/canonical-tokens.test.ts index 60f8c59..bbe8858 100644 --- a/services/token-aggregation/src/config/canonical-tokens.test.ts +++ b/services/token-aggregation/src/config/canonical-tokens.test.ts @@ -44,6 +44,41 @@ describe('canonical cW token catalog', () => { expect(getCanonicalTokenByAddress(56, '0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55')?.symbol).toBe('cWUSDW'); }); + it('keeps Cronos and the broader wrapped fiat/commodity family in the canonical cW mesh', () => { + const cronosCwUsdc = getCanonicalTokenBySymbol(25, 'cWUSDC'); + expect(cronosCwUsdc).toMatchObject({ + symbol: 'cWUSDC', + type: 'w', + currencyCode: 'USD', + }); + expect(cronosCwUsdc?.addresses[25]).toBe('0x932566E5bB6BEBF6B035B94f3DE1f75f126304Ec'); + expect(getCanonicalTokenByAddress(25, '0x932566E5bB6BEBF6B035B94f3DE1f75f126304Ec')?.symbol).toBe('cWUSDC'); + + const expected = [ + ['cWEURC', 'EUR', '0x7574d37F42528B47c88962931e48FC61608a4050'], + ['cWEURT', 'EUR', '0x9f833b4f1012F52eb3317b09922a79c6EdFca77D'], + ['cWGBPC', 'GBP', '0xe5c65A76A541368d3061fe9E7A2140cABB903dbF'], + ['cWGBPT', 'GBP', '0xBb58fa16bAc8E789f09C14243adEE6480D8213A2'], + ['cWAUDC', 'AUD', '0xff3084410A732231472Ee9f93F5855dA89CC5254'], + ['cWJPYC', 'JPY', '0x52aD62B8bD01154e2A4E067F8Dc4144C9988d203'], + ['cWCHFC', 'CHF', '0xB55F49D6316322d5caA96D34C6e4b1003BD3E670'], + ['cWCADC', 'CAD', '0x32aD687F24F77bF8C86605c202c829163Ac5Ab36'], + ['cWXAUC', 'XAU', '0xf1B771c95573113E993374c0c7cB2dc1a7908B12'], + ['cWXAUT', 'XAU', '0xD517C0cF7013f988946A468c880Cc9F8e2A4BCbE'], + ] as const; + + for (const [symbol, currencyCode, cronosAddress] of expected) { + const token = getCanonicalTokenBySymbol(25, symbol); + expect(token).toMatchObject({ + symbol, + type: 'w', + currencyCode, + }); + expect(token?.addresses[25]).toBe(cronosAddress); + expect(getCanonicalTokenByAddress(25, cronosAddress)?.symbol).toBe(symbol); + } + }); + it('surfaces cUSDW on Chain 138 as the repo-native USDW hub asset', () => { const cusdw = getCanonicalTokenBySymbol(138, 'cUSDW'); expect(cusdw).toMatchObject({ diff --git a/services/token-aggregation/src/config/canonical-tokens.ts b/services/token-aggregation/src/config/canonical-tokens.ts index 09f755e..ddde2cd 100644 --- a/services/token-aggregation/src/config/canonical-tokens.ts +++ b/services/token-aggregation/src/config/canonical-tokens.ts @@ -70,7 +70,7 @@ const LEGACY_CHAIN_ENV_SUFFIX: Partial> = { }; /** L2/mainnet chain IDs for cUSDT/cUSDC multichain (env: CUSDT_ADDRESS_56, CUSDC_ADDRESS_137, etc.) */ const L2_CHAIN_IDS = [1, 56, 137, 10, 42161, 8453, 43114, 25, 100, 42220, 1111] as const; -const GRU_CW_CHAIN_IDS = [1, 56, 137, 10, 42161, 8453, 43114, 100, 42220] as const; +const GRU_CW_CHAIN_IDS = [1, 10, 25, 56, 100, 137, 8453, 42161, 42220, 43114] as const; const BTC_CW_CHAIN_IDS = [1, 10, 25, 56, 100, 137, 42161, 42220, 43114, 8453, 1111] as const; const ETH_MAINNET_CW_CHAIN_IDS = [1] as const; const ETH_L2_CW_CHAIN_IDS = [10, 42161, 8453] as const; @@ -165,33 +165,156 @@ const FALLBACK_ADDRESSES: Record>> = { cWAUSDT: { [56]: '0xe1a51Bc037a79AB36767561B147eb41780124934', [137]: '0xf12e262F85107df26741726b074606CaFa24AAe7', - [43114]: '0xff3084410A732231472Ee9f93F5855dA89CC5254', [42220]: '0xC158b6cD3A3088C52F797D41f5Aa02825361629e', + [43114]: '0xff3084410A732231472Ee9f93F5855dA89CC5254', }, cWUSDC: { [1]: '0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a', - [56]: '0x5355148C4740fcc3D7a96F05EdD89AB14851206b', - [137]: '0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4', - [100]: '0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4', [10]: '0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105', - [42161]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF', + [25]: '0x932566E5bB6BEBF6B035B94f3DE1f75f126304Ec', + [56]: '0x5355148C4740fcc3D7a96F05EdD89AB14851206b', + [100]: '0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4', + [137]: '0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4', [8453]: '0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105', - [43114]: '0x0C242b513008Cd49C89078F5aFb237A3112251EB', + [42161]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF', [42220]: '0x4C38F9A5ed68A04cd28a72E8c68C459Ec34576f3', + [43114]: '0x0C242b513008Cd49C89078F5aFb237A3112251EB', }, cWUSDT: { [1]: '0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE', - [56]: '0x9a1D0dBEE997929ED02fD19E0E199704d20914dB', - [137]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF', - [100]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF', [10]: '0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6', - [42161]: '0x73ADaF7dBa95221c080db5631466d2bC54f6a76B', + [25]: '0x72948a7a813B60b37Cd0c920C4657DbFF54312b8', + [56]: '0x9a1D0dBEE997929ED02fD19E0E199704d20914dB', + [100]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF', + [137]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF', [8453]: '0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6', - [43114]: '0x8142BA530B08f3950128601F00DaaA678213DFdf', + [42161]: '0x73ADaF7dBa95221c080db5631466d2bC54f6a76B', [42220]: '0x73376eB92c16977B126dB9112936A20Fa0De3442', + [43114]: '0x8142BA530B08f3950128601F00DaaA678213DFdf', + }, + cWEURC: { + [1]: '0xD4aEAa8cD3fB41Dc8437FaC7639B6d91B60A5e8d', + [10]: '0x4ab39b5bab7b463435209a9039bd40cf241f5a82', + [25]: '0x7574d37F42528B47c88962931e48FC61608a4050', + [56]: '0x50b073d0D1D2f002745cb9FC28a057d5be84911c', + [100]: '0x25603ae4bff0b71d637b3573d1b6657f5f6d17ef', + [137]: '0x3CD9ee18db7ad13616FCC1c83bC6098e03968E66', + [8453]: '0xcb145ba9a370681e3545f60e55621ebf218b1031', + [42161]: '0x2a0023ad5ce1ac6072b454575996dffb1bb11b16', + [42220]: '0xb6D2f38b9015F32ccE8818509c712264E7fceeD3', + [43114]: '0x84353ed1f0c7a703a17abad19b0db15bc9a5e3e5', + }, + cWEURT: { + [1]: '0x855d74FFB6CF75721a9bAbc8B2ed35c8119241dC', + [10]: '0x6f521cd9fcf7884cd4e9486c7790e818638e09dd', + [25]: '0x9f833b4f1012F52eb3317b09922a79c6EdFca77D', + [56]: '0x1ED9E491A5eCd53BeF21962A5FCE24880264F63f', + [100]: '0x8e54c52d34a684e22865ac9f2d7c27c30561a7b9', + [137]: '0xBeF5A0Bcc0E77740c910f197138cdD90F98d2427', + [8453]: '0x73e0cf8bf861d376b3a4c87c136f975027f045ff', + [42161]: '0x22b98130ab4d9c355512b25ade4c35e75a4e7e89', + [42220]: '0x7e6fB8D80f81430e560F8232b2A4fd06249d74ce', + [43114]: '0xfc7d256e48253f7a7e08f0e55b9ff7039eb2524c', + }, + cWGBPC: { + [1]: '0xc074007dc0bfb384b1cf6426a56287ed23fe4d52', + [10]: '0x3f8c409c6072a2b6a4ff17071927ba70f80c725f', + [25]: '0xe5c65A76A541368d3061fe9E7A2140cABB903dbF', + [56]: '0x8b6EE72001cAFcb21D56a6c4686D6Db951d499A6', + [100]: '0x4d9bc6c74ba65e37c4139f0aec9fc5ddff28dcc4', + [137]: '0x948690147D2e50ffe50C5d38C14125aD6a9FA036', + [8453]: '0x2a0023ad5ce1ac6072b454575996dffb1bb11b16', + [42161]: '0xa846aead3071df1b6439d5d813156ace7c2c1da1', + [42220]: '0xE37c332a88f112F9e039C5d92D821402A89c7052', + [43114]: '0xbdf0c4ea1d81e8e769b0f41389a2c733e3ff723e', + }, + cWGBPT: { + [1]: '0x1dDF9970F01c76A692Fdba2706203E6f16e0C46F', + [10]: '0x456373d095d6b9260f01709f93fccf1d8aa14d11', + [25]: '0xBb58fa16bAc8E789f09C14243adEE6480D8213A2', + [56]: '0xA6eFb8783C8ad2740ec880e46D4f7E608E893B1B', + [100]: '0x9f6d2578003fe04e58a9819a4943732f2a203a61', + [137]: '0x58a8D8F78F1B65c06dAd7542eC46b299629A60dd', + [8453]: '0x22b98130ab4d9c355512b25ade4c35e75a4e7e89', + [42161]: '0x29828e9ab2057cd3df3c9211455ae1f76e53d2af', + [42220]: '0x1dBa81f91f1BeC47FFf60eC3e7DeD780ad9968E3', + [43114]: '0x4611d3424e059392a52b957e508273bc761c80f2', + }, + cWAUDC: { + [1]: '0x5020Db641B3Fc0dAbBc0c688C845bc4E3699f35F', + [10]: '0x25603ae4bff0b71d637b3573d1b6657f5f6d17ef', + [25]: '0xff3084410A732231472Ee9f93F5855dA89CC5254', + [56]: '0x7062f35567BBAb4d98dc33af03B0d14Df42294D5', + [100]: '0xddc4063f770f7c49d00b5a10fb552e922aa39b2c', + [137]: '0xFb4B6Cc81211F7d886950158294A44C312abCA29', + [8453]: '0xa846aead3071df1b6439d5d813156ace7c2c1da1', + [42161]: '0xc1535e88578d984f12eab55863376b8d8b9fb05a', + [42220]: '0x2d3a2ED4Ca4d69912d217c305EE921609F7906A8', + [43114]: '0x04e1e22b0d41e99f4275bd40a50480219bc9a223', + }, + cWJPYC: { + [1]: '0x07EEd0D7dD40984e47B9D3a3bdded1c536435582', + [10]: '0x8e54c52d34a684e22865ac9f2d7c27c30561a7b9', + [25]: '0x52aD62B8bD01154e2A4E067F8Dc4144C9988d203', + [56]: '0x5fbCE65524211BC1bFb0309fd9EE09E786c6D097', + [100]: '0x145e8e8c49b6a021969dd9d2c01c8fea44374f61', + [137]: '0xf9f5D0ACD71C76F9476F10B3F3d3E201F0883C68', + [8453]: '0x29828e9ab2057cd3df3c9211455ae1f76e53d2af', + [42161]: '0xdc383c489533a4dd9a6bd3007386e25d5078b878', + [42220]: '0x0b39F47D2E68aB0eB18d4b637Bbd1dD8E97cFbB5', + [43114]: '0x3714b1a312e0916c7dcdc4edf480fc0339e59a59', + }, + cWCHFC: { + [1]: '0x0F91C5E6Ddd46403746aAC970D05d70FFe404780', + [10]: '0x4d9bc6c74ba65e37c4139f0aec9fc5ddff28dcc4', + [25]: '0xB55F49D6316322d5caA96D34C6e4b1003BD3E670', + [56]: '0xD9f8710caeeBA3b3D423D7D14a918701426B5ef3', + [100]: '0x46d90d7947f1139477c206c39268923b99cf09e4', + [137]: '0xeE17bB0322383fecCA2784fbE2d4CD7d02b1905B', + [8453]: '0xc1535e88578d984f12eab55863376b8d8b9fb05a', + [42161]: '0x7e4b4682453bcce19ec903fb69153d3031986bc4', + [42220]: '0x8142BA530B08f3950128601F00DaaA678213DFdf', + [43114]: '0xc2fa05f12a75ac84ea778af9d6935ca807275e55', + }, + cWCADC: { + [1]: '0x209FE32fe7B541751D190ae4e50cd005DcF8EDb4', + [10]: '0x9f6d2578003fe04e58a9819a4943732f2a203a61', + [25]: '0x32aD687F24F77bF8C86605c202c829163Ac5Ab36', + [56]: '0x9AE7a6B311584D60Fa93f973950d609061875775', + [100]: '0xa7133c78e0ec74503a5941bcbd44257615b6b4f6', + [137]: '0xc9750828124D4c10e7a6f4B655cA8487bD3842EB', + [8453]: '0xdc383c489533a4dd9a6bd3007386e25d5078b878', + [42161]: '0xcc6ae6016d564e9ab82aaff44d65e05a9b18951c', + [42220]: '0x0C242b513008Cd49C89078F5aFb237A3112251EB', + [43114]: '0x1872e033b30f3ce0498847926857433e0146394e', + }, + cWXAUC: { + [1]: '0x572Be0fa8CA0534d642A567CEDb398B771D8a715', + [10]: '0xddc4063f770f7c49d00b5a10fb552e922aa39b2c', + [25]: '0xf1B771c95573113E993374c0c7cB2dc1a7908B12', + [56]: '0xCB145bA9A370681e3545F60e55621eBf218B1031', + [100]: '0x23873b85cfeb343eb952618e8c9e9bfb7f6a0d45', + [137]: '0x328Cd365Bb35524297E68ED28c6fF2C9557d1363', + [8453]: '0x7e4b4682453bcce19ec903fb69153d3031986bc4', + [42161]: '0xa7762b63c4871581885ad17c5714ebb286a7480b', + [42220]: '0x61D642979eD75c1325f35b9275C5A7FE97F22451', + [43114]: '0x4f95297c23d9f4a1032b1c6a2e553225cb175bee', + }, + cWXAUT: { + [1]: '0xACE1DBF857549a11aF1322e1f91F2F64b029c906', + [10]: '0x145e8e8c49b6a021969dd9d2c01c8fea44374f61', + [25]: '0xD517C0cF7013f988946A468c880Cc9F8e2A4BCbE', + [56]: '0x73E0CF8BF861D376B3a4C87c136F975027f045ff', + [100]: '0xc6189d404dc60cae7b48e2190e44770a03193e5f', + [137]: '0x9e6044d730d4183bF7a666293d257d035Fba6d44', + [8453]: '0xcc6ae6016d564e9ab82aaff44d65e05a9b18951c', + [42161]: '0x66568899ffe8f00b25dc470e878b65a478994e76', + [42220]: '0x30751782486eed825187C1EAe5DE4b4baD428AaE', + [43114]: '0xd2b4dbf2f6bd6704e066d752eec61fb0be953fd3', }, cWUSDW: { [56]: '0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55', + [42220]: '0x176a1b6Aa59F24B3aa65F2b697AB262Bca9093B5', [43114]: '0xcfdCe5E660FC2C8052BDfa7aEa1865DD753411Ae', }, cWBTC: { @@ -236,7 +359,7 @@ const FALLBACK_ADDRESSES: Record>> = { cWWEMIX: { [1111]: '0xc111000000000000000000000000000000000457', }, - // Compliant Fiat on Chain 138 — from DeployCompliantFiatTokens (2026-02-27) + // Compliant Fiat on Chain 138 - from DeployCompliantFiatTokens (2026-02-27) cEURC: { [CHAIN_138]: '0x8085961F9cF02b4d800A3c6d386D31da4B34266a' }, cEURT: { [CHAIN_138]: '0xdf4b71c61E5912712C1Bdd451416B9aC26949d72' }, cGBPC: { [CHAIN_138]: '0x003960f16D9d34F2e98d62723B6721Fb92074aD2' }, @@ -247,9 +370,10 @@ const FALLBACK_ADDRESSES: Record>> = { cCADC: { [CHAIN_138]: '0x54dBd40cF05e15906A2C21f600937e96787f5679' }, cXAUC: { [CHAIN_138]: '0x290E52a8819A4fbD0714E517225429aA2B70EC6b' }, cXAUT: { [CHAIN_138]: '0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E' }, + LINK: { [CHAIN_138]: '0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03' }, WETH: { [CHAIN_138]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' }, WETH10: { [CHAIN_138]: '0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f' }, - // ISO-4217W on Cronos (25) — from DeployISO4217WSystem + // ISO-4217W on Cronos (25) - from DeployISO4217WSystem USDW: { [CHAIN_25]: '0x948690147D2e50ffe50C5d38C14125aD6a9FA036' }, EURW: { [CHAIN_25]: '0x58a8D8F78F1B65c06dAd7542eC46b299629A60dd' }, GBPW: { [CHAIN_25]: '0xFb4B6Cc81211F7d886950158294A44C312abCA29' }, @@ -451,6 +575,16 @@ export const CANONICAL_TOKENS: CanonicalTokenSpec[] = [ { symbol: 'cWAUSDT', name: 'Alltra USD Token (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form for the live Chain 138 cAUSDT surface.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWAUSDT', id)])) } }, { symbol: 'cWUSDC', name: 'USD Coin (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDC', id)])) } }, { symbol: 'cWUSDT', name: 'Tether USD (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDT', id)])) } }, + { symbol: 'cWEURC', name: 'Euro Coin (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'EUR', description: 'Public-network mirrored transport form of canonical Chain 138 cEURC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWEURC', id)])) } }, + { symbol: 'cWEURT', name: 'Tether EUR (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'EUR', description: 'Public-network mirrored transport form of canonical Chain 138 cEURT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWEURT', id)])) } }, + { symbol: 'cWGBPC', name: 'Pound Sterling (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'GBP', description: 'Public-network mirrored transport form of canonical Chain 138 cGBPC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWGBPC', id)])) } }, + { symbol: 'cWGBPT', name: 'Tether GBP (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'GBP', description: 'Public-network mirrored transport form of canonical Chain 138 cGBPT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWGBPT', id)])) } }, + { symbol: 'cWAUDC', name: 'Australian Dollar (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'AUD', description: 'Public-network mirrored transport form of canonical Chain 138 cAUDC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWAUDC', id)])) } }, + { symbol: 'cWJPYC', name: 'Japanese Yen (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'JPY', description: 'Public-network mirrored transport form of canonical Chain 138 cJPYC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWJPYC', id)])) } }, + { symbol: 'cWCHFC', name: 'Swiss Franc (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'CHF', description: 'Public-network mirrored transport form of canonical Chain 138 cCHFC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWCHFC', id)])) } }, + { symbol: 'cWCADC', name: 'Canadian Dollar (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'CAD', description: 'Public-network mirrored transport form of canonical Chain 138 cCADC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWCADC', id)])) } }, + { symbol: 'cWXAUC', name: 'Gold (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'XAU', registryFamily: 'commodity', description: 'Public-network mirrored transport form of canonical Chain 138 cXAUC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWXAUC', id)])) } }, + { symbol: 'cWXAUT', name: 'Tether XAU (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'XAU', registryFamily: 'commodity', description: 'Public-network mirrored transport form of canonical Chain 138 cXAUT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWXAUT', id)])) } }, { symbol: 'cWUSDW', name: 'USD W (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDW.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDW', id)])) } }, { symbol: 'WETH', @@ -472,6 +606,16 @@ export const CANONICAL_TOKENS: CanonicalTokenSpec[] = [ description: 'Chain 138 WETH10 pilot wrapped ETH surface used by DODO v3 routing and flash-capable paths.', addresses: { [CHAIN_138]: addr('WETH10', CHAIN_138) || '' }, }, + { + symbol: 'LINK', + name: 'Chainlink Token', + type: 'base', + decimals: 18, + currencyCode: 'LINK', + registryFamily: 'unclassified', + description: 'Chain 138 LINK token used for CCIP and oracle fee accounting.', + addresses: { [CHAIN_138]: addr('LINK', CHAIN_138) || '' }, + }, { symbol: 'cWBTC', name: 'Bitcoin (Compliant Wrapped Monetary Unit)', @@ -730,7 +874,18 @@ export function resolveCanonicalQuoteAddress(chainId: number, address: string): const IPFS_GATEWAY = 'https://ipfs.io/ipfs'; const GRU_LOGO_BASE = 'https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru'; -const ETH_LOGO = `${IPFS_GATEWAY}/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong`; +const ETH_LOGO = '/api/v1/report/logo/ETH'; +const LINK_LOGO = '/api/v1/report/logo/LINK'; +const GAS_NATIVE_LOGO_BY_CODE: Record = { + ETH: ETH_LOGO, + BNB: '/api/v1/report/logo/BNB', + POL: '/api/v1/report/logo/POL', + AVAX: '/api/v1/report/logo/AVAX', + CRO: '/api/v1/report/logo/CRO', + XDAI: '/api/v1/report/logo/XDAI', + CELO: '/api/v1/report/logo/CELO', + WEMIX: '/api/v1/report/logo/WEMIX', +}; const USDC_LOGO = `${GRU_LOGO_BASE}/cUSDC.svg`; const USDT_LOGO = `${GRU_LOGO_BASE}/cUSDT.svg`; const BTC_LOGO = 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/bitcoin/info/logo.png'; @@ -750,8 +905,10 @@ const LOGO_BY_SYMBOL: Record = { cWUSDC: USDC_LOGO, cWUSDT: USDT_LOGO, cWUSDW: USDC_LOGO, + cWEMIX: GAS_NATIVE_LOGO_BY_CODE.WEMIX, WETH: ETH_LOGO, WETH10: ETH_LOGO, + LINK: LINK_LOGO, cEURC: `${GRU_LOGO_BASE}/cEURC.svg`, cEURT: `${GRU_LOGO_BASE}/cEURT.svg`, cGBPC: `${GRU_LOGO_BASE}/cGBPC.svg`, @@ -781,6 +938,15 @@ export function getLogoUriForSpec(spec: CanonicalTokenSpec): string { if (spec.logoUrl) return spec.logoUrl; const bySymbol = LOGO_BY_SYMBOL[spec.symbol]; if (bySymbol) return bySymbol; + const gasLogo = spec.registryFamily === 'gas_native' && spec.currencyCode + ? GAS_NATIVE_LOGO_BY_CODE[spec.currencyCode.toUpperCase()] + : undefined; + if (gasLogo) return gasLogo; + if (spec.symbol.startsWith('cW')) { + const hubSymbol = `c${spec.symbol.slice(2)}`; + const hubSpec = CANONICAL_TOKENS.find((t) => t.symbol === hubSymbol); + if (hubSpec && hubSpec.symbol !== spec.symbol) return getLogoUriForSpec(hubSpec); + } if (spec.symbol.startsWith('ac')) return getLogoUriForSpec(CANONICAL_TOKENS.find((t) => t.symbol === spec.symbol.replace('ac', 'c')) || spec); if (spec.symbol.startsWith('vdc') || spec.symbol.startsWith('sdc')) { const base = spec.symbol.replace(/^(vd|sd)c/, 'c'); diff --git a/services/token-aggregation/src/config/chains.ts b/services/token-aggregation/src/config/chains.ts index c82958c..be12534 100644 --- a/services/token-aggregation/src/config/chains.ts +++ b/services/token-aggregation/src/config/chains.ts @@ -81,7 +81,7 @@ export const CHAIN_CONFIGS: Record = { 137: { chainId: 137, name: 'Polygon', - rpcUrl: process.env.CHAIN_137_RPC_URL || 'https://polygon-rpc.com', + rpcUrl: process.env.CHAIN_137_RPC_URL || 'https://polygon-bor-rpc.publicnode.com', explorerUrl: 'https://polygonscan.com', nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 }, blockTime: 2, diff --git a/services/token-aggregation/src/config/deployment-status.ts b/services/token-aggregation/src/config/deployment-status.ts index 3de3873..5d2d905 100644 --- a/services/token-aggregation/src/config/deployment-status.ts +++ b/services/token-aggregation/src/config/deployment-status.ts @@ -69,6 +69,9 @@ function buildDeploymentStatusCandidates(): string[] { process.env.DEPLOYMENT_STATUS_JSON_PATH, process.env.CW_REGISTRY_JSON_PATH, process.env.CROSS_CHAIN_PMM_DEPLOYMENT_STATUS_PATH, + process.env.PROXMOX_REPO_ROOT + ? path.resolve(process.env.PROXMOX_REPO_ROOT, 'cross-chain-pmm-lps/config/deployment-status.json') + : undefined, path.resolve(process.cwd(), 'cross-chain-pmm-lps/config/deployment-status.json'), path.resolve(process.cwd(), '..', 'cross-chain-pmm-lps/config/deployment-status.json'), path.resolve(process.cwd(), '..', '..', 'cross-chain-pmm-lps/config/deployment-status.json'), diff --git a/services/token-aggregation/src/config/gru-v2-deployment-pools.ts b/services/token-aggregation/src/config/gru-v2-deployment-pools.ts index 95ed486..def187a 100644 --- a/services/token-aggregation/src/config/gru-v2-deployment-pools.ts +++ b/services/token-aggregation/src/config/gru-v2-deployment-pools.ts @@ -7,6 +7,8 @@ export interface GruV2DeploymentPoolRow { chainId: number; chainName: string; section: GruV2PmmSection; + status: 'live' | 'routing_enabled' | 'configured' | 'proof_required'; + statusReason: string; baseSymbol: string; quoteSymbol: string; baseAddress: string; @@ -101,6 +103,16 @@ export function buildGruV2PoolRegistryFromDeploymentData(data: DeploymentStatusF chainId, chainName, section, + status: + pool.publicRoutingEnabled === true + ? 'routing_enabled' + : poolAddress.startsWith('0x') + ? 'live' + : 'configured', + statusReason: + pool.publicRoutingEnabled === true + ? 'Pool address is configured in deployment-status and public routing is enabled.' + : 'Pool address is configured in deployment-status; routing enablement is not asserted.', baseSymbol, quoteSymbol, baseAddress, diff --git a/services/token-aggregation/src/config/networks.ts b/services/token-aggregation/src/config/networks.ts index e1d52ce..8967f35 100644 --- a/services/token-aggregation/src/config/networks.ts +++ b/services/token-aggregation/src/config/networks.ts @@ -34,8 +34,9 @@ export const NETWORKS: NetworkEntry[] = [ nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, blockExplorerUrls: ['https://explorer.d-bis.org'], iconUrls: [ + 'https://explorer.d-bis.org/api/v1/report/logo/chain-138', + 'https://explorer.d-bis.org/token-icons/chain-138.png', 'https://explorer.d-bis.org/favicon.ico', - 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png', ], oracles: [ { name: 'ETH/USD', address: '0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6', decimals: 8 }, @@ -87,7 +88,13 @@ export const NETWORKS: NetworkEntry[] = [ chainId: '0x89', chainIdDecimal: 137, chainName: 'Polygon', - rpcUrls: ['https://polygon-rpc.com', 'https://rpc.ankr.com/polygon'], + rpcUrls: [ + 'https://polygon-bor-rpc.publicnode.com', + 'https://1rpc.io/matic', + 'https://polygon.drpc.org', + 'https://polygon-rpc.com', + 'https://rpc.ankr.com/polygon', + ], nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 }, blockExplorerUrls: ['https://polygonscan.com'], iconUrls: ['https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/polygon/info/logo.png'], diff --git a/services/token-aggregation/src/database/client.ts b/services/token-aggregation/src/database/client.ts index 7844e97..a9b5e7c 100644 --- a/services/token-aggregation/src/database/client.ts +++ b/services/token-aggregation/src/database/client.ts @@ -26,6 +26,7 @@ export function getDatabasePool(): Pool { connectionString: process.env.DATABASE_URL, min: parseInt(process.env.DATABASE_POOL_MIN || '2', 10), max: parseInt(process.env.DATABASE_POOL_MAX || '10', 10), + connectionTimeoutMillis: parseInt(process.env.DATABASE_CONNECTION_TIMEOUT_MS || '3000', 10), }; // If connectionString is not provided, use individual config diff --git a/services/token-aggregation/src/database/repositories/market-data-repo.ts b/services/token-aggregation/src/database/repositories/market-data-repo.ts index 917c700..37c697d 100644 --- a/services/token-aggregation/src/database/repositories/market-data-repo.ts +++ b/services/token-aggregation/src/database/repositories/market-data-repo.ts @@ -19,7 +19,16 @@ export class MarketDataRepository { return code === '42P01' || (message.includes('relation "') && message.includes('" does not exist')); } + private shouldUseReadFallback(error: unknown): boolean { + if (this.isMissingRelationError(error)) return true; + if (String(process.env.TOKEN_AGGREGATION_DB_READ_FALLBACK ?? '1').toLowerCase() === '0') return false; + const message = (error as { message?: string })?.message || ''; + const code = (error as { code?: string })?.code || ''; + return ['ETIMEDOUT', 'ECONNREFUSED', 'ENOTFOUND'].includes(code) || /timeout|connect/i.test(message); + } + async getMarketData(chainId: number, tokenAddress: string): Promise { + if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return null; try { const result = await this.pool.query( `SELECT chain_id, token_address, price_usd, price_change_24h, volume_24h, volume_7d, volume_30d, @@ -49,7 +58,7 @@ export class MarketDataRepository { lastUpdated: row.last_updated, }; } catch (error) { - if (this.isMissingRelationError(error)) { + if (this.shouldUseReadFallback(error)) { return null; } throw error; @@ -99,6 +108,7 @@ export class MarketDataRepository { } async getTopTokensByVolume(chainId: number, limit: number = 50): Promise { + if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return []; try { const result = await this.pool.query( `SELECT chain_id, token_address, price_usd, price_change_24h, volume_24h, volume_7d, volume_30d, @@ -125,7 +135,7 @@ export class MarketDataRepository { lastUpdated: row.last_updated, })); } catch (error) { - if (this.isMissingRelationError(error)) { + if (this.shouldUseReadFallback(error)) { return []; } throw error; @@ -133,6 +143,7 @@ export class MarketDataRepository { } async getTopTokensByLiquidity(chainId: number, limit: number = 50): Promise { + if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return []; try { const result = await this.pool.query( `SELECT chain_id, token_address, price_usd, price_change_24h, volume_24h, volume_7d, volume_30d, @@ -159,7 +170,7 @@ export class MarketDataRepository { lastUpdated: row.last_updated, })); } catch (error) { - if (this.isMissingRelationError(error)) { + if (this.shouldUseReadFallback(error)) { return []; } throw error; diff --git a/services/token-aggregation/src/database/repositories/pool-repo.ts b/services/token-aggregation/src/database/repositories/pool-repo.ts index 4c5a28b..e4143c2 100644 --- a/services/token-aggregation/src/database/repositories/pool-repo.ts +++ b/services/token-aggregation/src/database/repositories/pool-repo.ts @@ -53,7 +53,16 @@ export class PoolRepository { return code === '42P01' || message.includes('relation "') && message.includes('" does not exist'); } + private shouldUseReadFallback(error: unknown): boolean { + if (this.isMissingRelationError(error)) return true; + if (String(process.env.TOKEN_AGGREGATION_DB_READ_FALLBACK ?? '1').toLowerCase() === '0') return false; + const message = (error as { message?: string })?.message || ''; + const code = (error as { code?: string })?.code || ''; + return ['ETIMEDOUT', 'ECONNREFUSED', 'ENOTFOUND'].includes(code) || /timeout|connect/i.test(message); + } + async getPool(chainId: number, poolAddress: string): Promise { + if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return null; try { const result = await this.pool.query( `SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type, @@ -70,7 +79,7 @@ export class PoolRepository { return this.mapRowToPool(result.rows[0]); } catch (error) { - if (this.isMissingRelationError(error)) { + if (this.shouldUseReadFallback(error)) { return null; } throw error; @@ -78,6 +87,7 @@ export class PoolRepository { } async getPoolsByChain(chainId: number, limit: number = 500): Promise { + if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return []; try { const result = await this.pool.query( `SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type, @@ -91,7 +101,7 @@ export class PoolRepository { ); return result.rows.map((row) => this.mapRowToPool(row)); } catch (error) { - if (this.isMissingRelationError(error)) { + if (this.shouldUseReadFallback(error)) { return []; } throw error; @@ -99,6 +109,7 @@ export class PoolRepository { } async getPoolsByToken(chainId: number, tokenAddress: string): Promise { + if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return []; try { const result = await this.pool.query( `SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type, @@ -112,7 +123,7 @@ export class PoolRepository { return result.rows.map((row) => this.mapRowToPool(row)); } catch (error) { - if (this.isMissingRelationError(error)) { + if (this.shouldUseReadFallback(error)) { return []; } throw error; diff --git a/services/token-aggregation/src/database/repositories/token-repo.ts b/services/token-aggregation/src/database/repositories/token-repo.ts index be4b039..71f5c02 100644 --- a/services/token-aggregation/src/database/repositories/token-repo.ts +++ b/services/token-aggregation/src/database/repositories/token-repo.ts @@ -46,7 +46,16 @@ export class TokenRepository { return code === '42P01' || (message.includes('relation "') && message.includes('" does not exist')); } + private shouldUseReadFallback(error: unknown): boolean { + if (this.isMissingRelationError(error)) return true; + if (String(process.env.TOKEN_AGGREGATION_DB_READ_FALLBACK ?? '1').toLowerCase() === '0') return false; + const message = (error as { message?: string })?.message || ''; + const code = (error as { code?: string })?.code || ''; + return ['ETIMEDOUT', 'ECONNREFUSED', 'ENOTFOUND'].includes(code) || /timeout|connect/i.test(message); + } + async getToken(chainId: number, address: string): Promise { + if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return null; try { const result = await this.pool.query( `SELECT chain_id, address, name, symbol, decimals, total_supply, logo_url, website_url, description, verified @@ -73,7 +82,7 @@ export class TokenRepository { verified: row.verified, }; } catch (error) { - if (this.isMissingRelationError(error)) { + if (this.shouldUseReadFallback(error)) { return null; } throw error; @@ -81,6 +90,7 @@ export class TokenRepository { } async getTokens(chainId: number, limit: number = 50, offset: number = 0): Promise { + if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return []; try { const result = await this.pool.query( `SELECT chain_id, address, name, symbol, decimals, total_supply, logo_url, website_url, description, verified @@ -104,7 +114,7 @@ export class TokenRepository { verified: row.verified, })); } catch (error) { - if (this.isMissingRelationError(error)) { + if (this.shouldUseReadFallback(error)) { return []; } throw error; diff --git a/services/token-aggregation/src/services/pmm-onchain-quote.ts b/services/token-aggregation/src/services/pmm-onchain-quote.ts index ff20b15..a1c2b5f 100644 --- a/services/token-aggregation/src/services/pmm-onchain-quote.ts +++ b/services/token-aggregation/src/services/pmm-onchain-quote.ts @@ -3,6 +3,7 @@ import { Contract, JsonRpcProvider } from 'ethers'; const POOL_ABI = [ 'function _BASE_TOKEN_() view returns (address)', 'function _QUOTE_TOKEN_() view returns (address)', + 'function getVaultReserve() view returns (uint256,uint256)', 'function querySellBase(address,uint256) view returns (uint256,uint256)', 'function querySellQuote(address,uint256) view returns (uint256,uint256)', ]; @@ -40,6 +41,25 @@ export async function pmmQuoteAmountOutFromChain(params: { } } +/** Best-effort reserve read for DODO-style PMM/DVM pools. */ +export async function pmmVaultReserveFromChain(params: { + rpcUrl: string; + poolAddress: string; +}): Promise<{ baseReserveRaw: bigint; quoteReserveRaw: bigint } | null> { + const { rpcUrl, poolAddress } = params; + try { + const provider = new JsonRpcProvider(rpcUrl); + const pool = new Contract(poolAddress, POOL_ABI, provider); + const [baseReserve, quoteReserve] = await pool.getVaultReserve(); + return { + baseReserveRaw: BigInt(baseReserve.toString()), + quoteReserveRaw: BigInt(quoteReserve.toString()), + }; + } catch { + return null; + } +} + /** RPC for PMM eth_call quotes on Chain 138 (optional; unset = skip on-chain override). */ export function resolvePmmQuoteRpcUrl(): string { return ( diff --git a/test/flash/DBISEngineXIndexedLiquidityVault.t.sol b/test/flash/DBISEngineXIndexedLiquidityVault.t.sol new file mode 100644 index 0000000..30d4db7 --- /dev/null +++ b/test/flash/DBISEngineXIndexedLiquidityVault.t.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {DBISEngineXIndexedLiquidityVault} from "../../contracts/flash/DBISEngineXIndexedLiquidityVault.sol"; +import {MockMintableToken} from "../dbis/MockMintableToken.sol"; + +contract MockEngineXUniswapV3Pool { + address public immutable token0; + address public immutable token1; + uint24 public immutable fee; + uint160 public sqrtPriceX96; + int24 public tick; + uint128 public liquidity; + + constructor(address token0_, address token1_, uint24 fee_) { + token0 = token0_; + token1 = token1_; + fee = fee_; + } + + function setSlot0(uint160 sqrtPriceX96_, int24 tick_) external { + sqrtPriceX96 = sqrtPriceX96_; + tick = tick_; + } + + function setLiquidity(uint128 liquidity_) external { + liquidity = liquidity_; + } + + function slot0() external view returns (uint160, int24, uint16, uint16, uint16, uint8, bool) { + return (sqrtPriceX96, tick, 0, 0, 0, 0, true); + } +} + +contract DBISEngineXIndexedLiquidityVaultTest is Test { + MockMintableToken internal cwusdc; + MockMintableToken internal usdc; + MockEngineXUniswapV3Pool internal pool; + DBISEngineXIndexedLiquidityVault internal vault; + + address internal constant RECIPIENT = address(0xD00D); + uint160 internal constant ONE_TO_ONE_SQRT_PRICE_X96 = 79_228_162_514_264_337_593_543_950_336; + bytes32 internal constant PROOF_ID = bytes32("indexed-proof"); + bytes32 internal constant SWAP_TX = bytes32(uint256(0xA1)); + bytes32 internal constant LIQUIDITY_TX = bytes32(uint256(0xB1)); + bytes32 internal constant ISO_HASH = bytes32(uint256(0x1001)); + bytes32 internal constant AUDIT_HASH = bytes32(uint256(0x1002)); + bytes32 internal constant PEG_HASH = bytes32(uint256(0x1003)); + + function setUp() public { + cwusdc = new MockMintableToken("Wrapped cWUSDC", "cWUSDC", 6, address(this)); + usdc = new MockMintableToken("USD Coin", "USDC", 6, address(this)); + pool = new MockEngineXUniswapV3Pool(address(cwusdc), address(usdc), 100); + pool.setSlot0(ONE_TO_ONE_SQRT_PRICE_X96, 0); + pool.setLiquidity(1_000_000); + cwusdc.mint(address(pool), 100_000_000); + usdc.mint(address(pool), 100_000_000); + + vault = new DBISEngineXIndexedLiquidityVault( + address(cwusdc), address(usdc), address(pool), address(this), 100, 1_000, 1_000_000 + ); + } + + function testRecordIndexedProofAnchorsPublicPoolState() public { + DBISEngineXIndexedLiquidityVault.IndexedProof memory proof = _proof(PROOF_ID); + + (uint160 sqrtPriceX96, int24 tick, uint128 liquidity) = vault.recordIndexedProof(proof); + + assertEq(sqrtPriceX96, ONE_TO_ONE_SQRT_PRICE_X96, "sqrt price"); + assertEq(tick, 0, "tick"); + assertEq(liquidity, 1_000_000, "liquidity"); + assertTrue(vault.usedProofIds(PROOF_ID), "proof consumed"); + } + + function testRejectsDuplicateProofId() public { + vault.recordIndexedProof(_proof(PROOF_ID)); + + vm.expectRevert(bytes("proof used")); + vault.recordIndexedProof(_proof(PROOF_ID)); + } + + function testRejectsTickDrift() public { + pool.setSlot0(ONE_TO_ONE_SQRT_PRICE_X96, 101); + + vm.expectRevert(bytes("tick drift too high")); + vault.recordIndexedProof(_proof(PROOF_ID)); + } + + function testRejectsInsufficientLiquidity() public { + pool.setLiquidity(999); + + vm.expectRevert(bytes("insufficient liquidity")); + vault.recordIndexedProof(_proof(PROOF_ID)); + } + + function testRejectsOversizedProofAmount() public { + DBISEngineXIndexedLiquidityVault.IndexedProof memory proof = _proof(PROOF_ID); + proof.exactOutputAmount = 1_000_001; + + vm.expectRevert(bytes("proof amount too high")); + vault.recordIndexedProof(proof); + } + + function testOperatorAllowlist() public { + vault.setOperatorAllowlistEnabled(true); + + vm.expectRevert(bytes("operator not approved")); + vm.prank(address(0xBEEF)); + vault.recordIndexedProof(_proof(PROOF_ID)); + + vault.setOperatorApproved(address(0xBEEF), true); + vm.prank(address(0xBEEF)); + vault.recordIndexedProof(_proof(PROOF_ID)); + assertTrue(vault.usedProofIds(PROOF_ID), "proof consumed"); + } + + function testPauseBlocksProofs() public { + vault.pause(); + + vm.expectRevert(bytes("paused")); + vault.recordIndexedProof(_proof(PROOF_ID)); + } + + function _proof(bytes32 proofId) internal pure returns (DBISEngineXIndexedLiquidityVault.IndexedProof memory) { + return DBISEngineXIndexedLiquidityVault.IndexedProof({ + proofId: proofId, + publicSwapTxHash: SWAP_TX, + liquidityTxHash: LIQUIDITY_TX, + outputRecipient: RECIPIENT, + exactOutputAmount: 100_000, + iso20022DocumentHash: ISO_HASH, + auditEnvelopeHash: AUDIT_HASH, + pegProofHash: PEG_HASH + }); + } +} diff --git a/test/flash/DBISEngineXSingleSidedDodoCwusdcVault.t.sol b/test/flash/DBISEngineXSingleSidedDodoCwusdcVault.t.sol new file mode 100644 index 0000000..9874b7a --- /dev/null +++ b/test/flash/DBISEngineXSingleSidedDodoCwusdcVault.t.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Test} from "forge-std/Test.sol"; +import {DBISEngineXSingleSidedDodoCwusdcVault} from + "../../contracts/flash/DBISEngineXSingleSidedDodoCwusdcVault.sol"; +import {MockMintableToken} from "../dbis/MockMintableToken.sol"; + +contract MockDodoPool { + using SafeERC20 for IERC20; + + address public immutable base; + address public immutable quote; + uint256 public baseReserve; + uint256 public quoteReserve; + + constructor(address base_, address quote_) { + base = base_; + quote = quote_; + } + + function _BASE_TOKEN_() external view returns (address) { + return base; + } + + function _QUOTE_TOKEN_() external view returns (address) { + return quote; + } + + function querySellBase(address, uint256 payBaseAmount) external pure returns (uint256 receiveQuoteAmount, uint256 mtFee) { + return (payBaseAmount, 0); + } + + function querySellQuote(address, uint256 payQuoteAmount) external pure returns (uint256 receiveBaseAmount, uint256 mtFee) { + return (payQuoteAmount, 0); + } + + function getVaultReserve() external view returns (uint256, uint256) { + return (baseReserve, quoteReserve); + } + + function buyShares(address) external returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare) { + uint256 baseBalance = IERC20(base).balanceOf(address(this)); + uint256 quoteBalance = IERC20(quote).balanceOf(address(this)); + baseShare = baseBalance - baseReserve; + quoteShare = quoteBalance - quoteReserve; + baseReserve = baseBalance; + quoteReserve = quoteBalance; + lpShare = baseShare < quoteShare ? baseShare : quoteShare; + } +} + +contract MockDodoIntegration { + using SafeERC20 for IERC20; + + function addLiquidity(address pool, uint256 baseAmount, uint256 quoteAmount) + external + returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare) + { + require(baseAmount > 0 && quoteAmount > 0, "zero amount"); + address base = MockDodoPool(pool)._BASE_TOKEN_(); + address quote = MockDodoPool(pool)._QUOTE_TOKEN_(); + IERC20(base).safeTransferFrom(msg.sender, pool, baseAmount); + IERC20(quote).safeTransferFrom(msg.sender, pool, quoteAmount); + return MockDodoPool(pool).buyShares(msg.sender); + } +} + +contract DBISEngineXSingleSidedDodoCwusdcVaultTest is Test { + MockMintableToken internal cwusdc; + MockMintableToken internal weth; + MockDodoIntegration internal integration; + MockDodoPool internal pool; + DBISEngineXSingleSidedDodoCwusdcVault internal vault; + + address internal constant FUNDER = address(0xF00D); + address internal constant OWNER = address(0xA11CE); + + function setUp() public { + cwusdc = new MockMintableToken("Wrapped cWUSDC", "cWUSDC", 6, address(this)); + weth = new MockMintableToken("Wrapped Ether", "WETH", 18, address(this)); + integration = new MockDodoIntegration(); + pool = new MockDodoPool(address(cwusdc), address(weth)); + vault = new DBISEngineXSingleSidedDodoCwusdcVault(address(cwusdc), address(weth), address(integration), OWNER); + + cwusdc.mint(FUNDER, 100_000_000); + weth.mint(FUNDER, 1 ether); + vm.startPrank(FUNDER); + cwusdc.approve(address(vault), type(uint256).max); + weth.approve(address(vault), type(uint256).max); + vm.stopPrank(); + } + + function testAcceptsSingleSidedCwusdcAsInventoryButNotExecutable() public { + vm.prank(FUNDER); + vault.depositCwusdc(10_000_000); + + ( + uint256 cwusdcBalance, + uint256 quoteBalance, + uint256 cwusdcInventory, + uint256 quoteInventory, + bool solvent, + bool executable + ) = vault.solvencyState(); + + assertEq(cwusdcBalance, 10_000_000, "cw balance"); + assertEq(quoteBalance, 0, "quote balance"); + assertEq(cwusdcInventory, 10_000_000, "cw inventory"); + assertEq(quoteInventory, 0, "quote inventory"); + assertTrue(solvent, "single-sided inventory is solvent"); + assertFalse(executable, "single-sided inventory is not executable DODO liquidity"); + } + + function testPromoteRequiresTwoSidedInventory() public { + vm.prank(OWNER); + vault.setDodoPool(address(pool)); + vm.prank(OWNER); + vault.setCanary(1_000, 1_000, 1_000, 1_000); + + vm.prank(FUNDER); + vault.depositCwusdc(10_000_000); + + vm.expectRevert(bytes("two-sided required")); + vm.prank(OWNER); + vault.promoteToDodo(1_000_000, 0, 0, 0, 0); + + vm.expectRevert(bytes("insufficient quote inventory")); + vm.prank(OWNER); + vault.promoteToDodo(1_000_000, 1, 0, 0, 0); + } + + function testPromotesTwoSidedInventoryAndPassesCanary() public { + vm.prank(OWNER); + vault.setDodoPool(address(pool)); + vm.prank(OWNER); + vault.setCanary(1_000, 1_000, 1_000, 1_000); + + vm.startPrank(FUNDER); + vault.depositCwusdc(10_000_000); + vault.depositQuote(1 ether); + vm.stopPrank(); + + vm.prank(OWNER); + (uint256 baseShare, uint256 quoteShare, uint256 lpShare) = + vault.promoteToDodo(2_000_000, 2_000_000, 2_000_000, 2_000_000, 2_000_000); + + assertEq(baseShare, 2_000_000, "base share"); + assertEq(quoteShare, 2_000_000, "quote share"); + assertEq(lpShare, 2_000_000, "lp share"); + assertEq(vault.accountedCwusdcInventory(), 8_000_000, "remaining cw inventory"); + assertEq(vault.accountedQuoteInventory(), 1 ether - 2_000_000, "remaining quote inventory"); + assertEq(cwusdc.balanceOf(address(pool)), 2_000_000, "pool cw balance"); + assertEq(weth.balanceOf(address(pool)), 2_000_000, "pool quote balance"); + assertTrue(vault.canaryPasses(), "canary passes"); + } + + function testCannotRescueAccountedInventory() public { + vm.prank(FUNDER); + vault.depositCwusdc(10_000_000); + + vm.expectRevert(bytes("cwusdc insolvent")); + vm.prank(OWNER); + vault.rescueUnaccountedToken(address(cwusdc), OWNER, 1); + } + + function testOwnerCanWithdrawAccountedInventory() public { + vm.prank(FUNDER); + vault.depositCwusdc(10_000_000); + + vm.prank(OWNER); + vault.withdrawCwusdcInventory(OWNER, 4_000_000); + + assertEq(vault.accountedCwusdcInventory(), 6_000_000, "inventory decremented"); + assertEq(cwusdc.balanceOf(OWNER), 4_000_000, "owner received"); + } +} diff --git a/test/flash/DBISEngineXVirtualBatchVault.t.sol b/test/flash/DBISEngineXVirtualBatchVault.t.sol index 9079a3d..60bbf5d 100644 --- a/test/flash/DBISEngineXVirtualBatchVault.t.sol +++ b/test/flash/DBISEngineXVirtualBatchVault.t.sol @@ -2,9 +2,32 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; +import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {DBISEngineXFlashProofBorrower} from "../../contracts/flash/DBISEngineXFlashProofBorrower.sol"; import {DBISEngineXVirtualBatchVault} from "../../contracts/flash/DBISEngineXVirtualBatchVault.sol"; import {MockMintableToken} from "../dbis/MockMintableToken.sol"; +contract EngineXFlashBorrower is IERC3156FlashBorrower { + bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + bool public repay = true; + + function setRepay(bool repay_) external { + repay = repay_; + } + + function onFlashLoan(address, address token, uint256 amount, uint256 fee, bytes calldata) + external + override + returns (bytes32) + { + if (repay) { + IERC20(token).transfer(msg.sender, amount + fee); + } + return _RETURN_VALUE; + } +} + contract DBISEngineXVirtualBatchVaultTest is Test { MockMintableToken internal cwusdc; MockMintableToken internal usdc; @@ -138,15 +161,7 @@ contract DBISEngineXVirtualBatchVaultTest is Test { ); vm.prank(USER); vault.runVirtualProofExactOutTo( - proofId, - LENDER_USDC, - 3, - OUTPUT_RECIPIENT, - exactOutput, - ROUNDING_RECEIVER, - ISO_HASH, - AUDIT_HASH, - PEG_HASH + proofId, LENDER_USDC, 3, OUTPUT_RECIPIENT, exactOutput, ROUNDING_RECEIVER, ISO_HASH, AUDIT_HASH, PEG_HASH ); assertEq(vault.poolCwusdcReserve(), LIVE_POOL_RESERVE, "pool cWUSDC reserve should not drift"); @@ -243,4 +258,154 @@ contract DBISEngineXVirtualBatchVaultTest is Test { PEG_HASH ); } + + function testWithdrawPoolLiquidityUpdatesAccountingAndPreservesMaintainedPool() public { + uint256 withdrawAmount = 10_000_000; + uint256 ownerCwusdcBefore = cwusdc.balanceOf(address(this)); + uint256 ownerUsdcBefore = usdc.balanceOf(address(this)); + + vault.withdrawPoolLiquidity(address(this), withdrawAmount, withdrawAmount); + + assertEq(vault.poolCwusdcReserve(), LIVE_POOL_RESERVE - withdrawAmount, "pool cWUSDC accounting"); + assertEq(vault.poolUsdcReserve(), LIVE_POOL_RESERVE - withdrawAmount, "pool USDC accounting"); + assertEq(vault.lenderUsdcAvailable(), LENDER_USDC, "lender accounting unchanged"); + assertEq(cwusdc.balanceOf(address(this)), ownerCwusdcBefore + withdrawAmount, "owner cWUSDC received"); + assertEq(usdc.balanceOf(address(this)), ownerUsdcBefore + withdrawAmount, "owner USDC received"); + } + + function testWithdrawPoolLiquidityRejectsBreakingMaintainedPool() public { + vm.expectRevert(bytes("would break maintained pool")); + vault.withdrawPoolLiquidity(address(this), 1, 0); + } + + function testWithdrawLenderUsdcUpdatesAccounting() public { + uint256 withdrawAmount = 1_000_000; + uint256 ownerUsdcBefore = usdc.balanceOf(address(this)); + + vault.withdrawLenderUsdc(address(this), withdrawAmount); + + assertEq(vault.lenderUsdcAvailable(), LENDER_USDC - withdrawAmount, "lender accounting"); + assertEq(vault.poolUsdcReserve(), LIVE_POOL_RESERVE, "pool accounting unchanged"); + assertEq(usdc.balanceOf(address(this)), ownerUsdcBefore + withdrawAmount, "owner USDC received"); + } + + function testGenericWithdrawCannotTouchAccountedBalances() public { + vm.expectRevert(bytes("accounting undercollateralized")); + vault.withdraw(address(usdc), address(this), 1); + } + + function testGenericWithdrawCanRescueUnaccountedTokens() public { + uint256 dust = 123; + usdc.mint(address(vault), dust); + uint256 ownerUsdcBefore = usdc.balanceOf(address(this)); + + vault.withdraw(address(usdc), address(this), dust); + + assertEq(vault.poolUsdcReserve(), LIVE_POOL_RESERVE, "pool accounting unchanged"); + assertEq(vault.lenderUsdcAvailable(), LENDER_USDC, "lender accounting unchanged"); + assertEq(usdc.balanceOf(address(this)), ownerUsdcBefore + dust, "owner receives unaccounted dust"); + } + + function testFlashLoanUsesLenderBucketAndCollectsFee() public { + EngineXFlashBorrower borrower = new EngineXFlashBorrower(); + uint256 amount = 1_000_000; + uint256 fee = vault.flashFee(address(usdc), amount); + usdc.mint(address(borrower), fee); + + vm.prank(USER); + vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(usdc), amount, ""); + + assertEq(vault.lenderUsdcAvailable(), LENDER_USDC + fee, "fee stays in lender bucket"); + assertEq(vault.totalFlashFeesCollectedUsdc(), fee, "fee accounting"); + assertEq(usdc.balanceOf(address(vault)), LIVE_POOL_RESERVE + LENDER_USDC + fee, "USDC backing"); + } + + function testFlashLoanCanPullRepaymentByAllowance() public { + EngineXFlashBorrower borrower = new EngineXFlashBorrower(); + uint256 amount = 1_000_000; + uint256 fee = vault.flashFee(address(usdc), amount); + usdc.mint(address(borrower), fee); + + borrower.setRepay(false); + vm.prank(address(borrower)); + usdc.approve(address(vault), type(uint256).max); + + vm.prank(USER); + vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(usdc), amount, ""); + + assertEq(vault.lenderUsdcAvailable(), LENDER_USDC + fee, "fee stays in lender bucket"); + assertEq(vault.totalFlashFeesCollectedUsdc(), fee, "fee accounting"); + } + + function testFlashLoanRejectsBorrowingPoolUsdc() public { + EngineXFlashBorrower borrower = new EngineXFlashBorrower(); + + vm.expectRevert(bytes("insufficient lender usdc")); + vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(usdc), LENDER_USDC + 1, ""); + } + + function testFlashLoanRejectsUnsupportedToken() public { + EngineXFlashBorrower borrower = new EngineXFlashBorrower(); + + vm.expectRevert(bytes("unsupported flash token")); + vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(cwusdc), 1, ""); + } + + function testFlashLoanCanBeCapped() public { + EngineXFlashBorrower borrower = new EngineXFlashBorrower(); + vault.setMaxFlashLoanAmount(999_999); + + vm.expectRevert(bytes("flash amount too high")); + vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(usdc), 1_000_000, ""); + } + + function testFlashLoanAllowlistRejectsUnapprovedBorrower() public { + EngineXFlashBorrower borrower = new EngineXFlashBorrower(); + vault.setFlashBorrowerAllowlistEnabled(true); + + vm.expectRevert(bytes("flash borrower not approved")); + vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(usdc), 1, ""); + } + + function testFlashLoanAllowlistAllowsApprovedBorrower() public { + EngineXFlashBorrower borrower = new EngineXFlashBorrower(); + uint256 amount = 1_000_000; + uint256 fee = vault.flashFee(address(usdc), amount); + usdc.mint(address(borrower), fee); + + vault.setFlashBorrowerAllowlistEnabled(true); + vault.setFlashBorrowerApproved(address(borrower), true); + + vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(usdc), amount, ""); + + assertEq(vault.lenderUsdcAvailable(), LENDER_USDC + fee, "fee stays in lender bucket"); + } + + function testPauseBlocksProofsAndFlashLoans() public { + EngineXFlashBorrower borrower = new EngineXFlashBorrower(); + vault.pause(); + + vm.expectRevert(bytes("paused")); + vm.prank(USER); + vault.runVirtualProof(bytes32("proof-paused"), LENDER_USDC, 1); + + vm.expectRevert(bytes("paused")); + vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(usdc), 1, ""); + + assertEq(vault.maxFlashLoan(address(usdc)), 0, "paused max flash"); + } + + function testEngineXFlashProofBorrowerRunsProofFlash() public { + DBISEngineXFlashProofBorrower borrower = + new DBISEngineXFlashProofBorrower(address(vault), address(usdc), address(this)); + uint256 amount = 1_000_000; + uint256 fee = vault.flashFee(address(usdc), amount); + bytes32 proofId = bytes32("flash-proof"); + usdc.mint(address(borrower), fee); + + borrower.runFlashProof(amount, proofId, ISO_HASH, AUDIT_HASH, PEG_HASH); + + assertTrue(borrower.usedProofIds(proofId), "proof consumed"); + assertEq(vault.lenderUsdcAvailable(), LENDER_USDC + fee, "fee stays in lender bucket"); + } } diff --git a/test/flash/DBISEngineXXautUsdcBorrowVault.t.sol b/test/flash/DBISEngineXXautUsdcBorrowVault.t.sol new file mode 100644 index 0000000..920073f --- /dev/null +++ b/test/flash/DBISEngineXXautUsdcBorrowVault.t.sol @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {DBISEngineXXautUsdcBorrowVault} from "../../contracts/flash/DBISEngineXXautUsdcBorrowVault.sol"; +import {MockMintableToken} from "../dbis/MockMintableToken.sol"; + +contract DBISEngineXXautUsdcBorrowVaultTest is Test { + MockMintableToken internal xaut; + MockMintableToken internal usdc; + MockMintableToken internal cwusdc; + DBISEngineXXautUsdcBorrowVault internal vault; + + address internal constant BORROWER = address(0xB0B); + address internal constant LENDER = address(0x1EAD); + address internal constant LIQUIDATOR = address(0xA11CE); + bytes32 internal constant PRICE_SOURCE_HASH = bytes32(uint256(0x5052494345)); + bytes32 internal constant SWAP_TX = bytes32(uint256(0x51574150)); + bytes32 internal constant ISO_HASH = bytes32(uint256(0x150)); + bytes32 internal constant AUDIT_HASH = bytes32(uint256(0xA0017)); + bytes32 internal constant PEG_HASH = bytes32(uint256(0x9E6)); + + uint256 internal constant XAUT_PRICE6 = 3_226_640_000; + uint256 internal constant LTV_BPS = 7_500; + uint256 internal constant LIQUIDATION_THRESHOLD_BPS = 8_000; + uint256 internal constant MIN_HEALTH_FACTOR_BPS = 11_000; + uint256 internal constant LIQUIDATION_BONUS_BPS = 500; + uint256 internal constant LENDER_USDC = 5_000_000_000; + + event CwusdcSourcedRepay( + address indexed account, + address indexed payer, + uint256 amount, + bytes32 indexed publicSwapTxHash, + bytes32 iso20022DocumentHash, + bytes32 auditEnvelopeHash, + bytes32 pegProofHash + ); + + function setUp() public { + xaut = new MockMintableToken("Tether Gold", "XAUt", 6, address(this)); + usdc = new MockMintableToken("USD Coin", "USDC", 6, address(this)); + cwusdc = new MockMintableToken("Wrapped cWUSDC", "cWUSDC", 6, address(this)); + + vault = new DBISEngineXXautUsdcBorrowVault( + address(xaut), + address(usdc), + address(cwusdc), + address(this), + XAUT_PRICE6, + LTV_BPS, + LIQUIDATION_THRESHOLD_BPS, + MIN_HEALTH_FACTOR_BPS, + LIQUIDATION_BONUS_BPS, + 0, + PRICE_SOURCE_HASH + ); + + usdc.mint(LENDER, LENDER_USDC); + vm.startPrank(LENDER); + usdc.approve(address(vault), type(uint256).max); + vault.fundLender(LENDER_USDC); + vm.stopPrank(); + + xaut.mint(BORROWER, 1_000_000); + usdc.mint(BORROWER, 1_000_000_000); + vm.startPrank(BORROWER); + xaut.approve(address(vault), type(uint256).max); + usdc.approve(address(vault), type(uint256).max); + vm.stopPrank(); + + usdc.mint(LIQUIDATOR, 1_000_000_000); + vm.prank(LIQUIDATOR); + usdc.approve(address(vault), type(uint256).max); + } + + function testBorrowRepayAndWithdrawCollateral() public { + vm.startPrank(BORROWER); + vault.supplyCollateral(1_000_000); + assertEq(vault.collateralValueUsd6(BORROWER), XAUT_PRICE6, "1 XAUt value"); + + vault.borrowUsdc(2_000_000_000, BORROWER); + assertEq(usdc.balanceOf(BORROWER), 3_000_000_000, "borrowed USDC"); + assertEq(vault.lenderUsdcAvailable(), 3_000_000_000, "lender bucket lent out"); + assertEq(vault.healthFactorBps(BORROWER), 12_906, "health factor"); + + vault.repayUsdc(2_000_000_000); + vault.withdrawCollateral(1_000_000, BORROWER); + vm.stopPrank(); + + (uint256 collateral, uint256 debt) = vault.positions(BORROWER); + assertEq(collateral, 0, "collateral closed"); + assertEq(debt, 0, "debt closed"); + assertEq(xaut.balanceOf(BORROWER), 1_000_000, "xaut returned"); + assertEq(vault.lenderUsdcAvailable(), LENDER_USDC, "lender restored"); + } + + function testBorrowRejectsDebtAboveEffectiveCollateralLimit() public { + vm.startPrank(BORROWER); + vault.supplyCollateral(1_000_000); + + vm.expectRevert(bytes("exceeds collateral")); + vault.borrowUsdc(2_400_000_000, BORROWER); + vm.stopPrank(); + } + + function testBorrowRejectsGlobalBorrowCap() public { + vault.setRiskParams(LTV_BPS, LIQUIDATION_THRESHOLD_BPS, MIN_HEALTH_FACTOR_BPS, LIQUIDATION_BONUS_BPS, 1_000_000_000); + + vm.startPrank(BORROWER); + vault.supplyCollateral(1_000_000); + + vm.expectRevert(bytes("max borrow exceeded")); + vault.borrowUsdc(1_000_000_001, BORROWER); + vm.stopPrank(); + } + + function testRepayFromCwusdcProofStillSettlesInUsdcAndAnchorsHashes() public { + vm.startPrank(BORROWER); + vault.supplyCollateral(1_000_000); + vault.borrowUsdc(1_000_000_000, BORROWER); + + vm.expectEmit(true, true, true, true, address(vault)); + emit CwusdcSourcedRepay(BORROWER, BORROWER, 250_000_000, SWAP_TX, ISO_HASH, AUDIT_HASH, PEG_HASH); + vault.repayUsdcFromCwusdcProof(250_000_000, SWAP_TX, ISO_HASH, AUDIT_HASH, PEG_HASH); + vm.stopPrank(); + + (, uint256 debt) = vault.positions(BORROWER); + assertEq(debt, 750_000_000, "debt reduced"); + assertEq(vault.totalCwusdcProofRepayUsdc(), 250_000_000, "proof-sourced repay counter"); + } + + function testLiquidationAfterPriceDrop() public { + vm.startPrank(BORROWER); + vault.supplyCollateral(1_000_000); + vault.borrowUsdc(2_000_000_000, BORROWER); + vm.stopPrank(); + + vault.setXautUsdPrice6(2_000_000_000, bytes32(uint256(0x44524f50))); + assertEq(vault.healthFactorBps(BORROWER), 8_000, "unhealthy after price drop"); + + vm.prank(LIQUIDATOR); + uint256 seized = vault.liquidate(BORROWER, 100_000_000); + + assertEq(seized, 52_500, "5 percent bonus on 0.05 XAUt"); + assertEq(xaut.balanceOf(LIQUIDATOR), 52_500, "liquidator receives XAUt"); + (, uint256 debt) = vault.positions(BORROWER); + assertEq(debt, 1_900_000_000, "debt after partial liquidation"); + } + + function testOwnerCanWithdrawOnlyUnborrowedLenderUsdc() public { + vm.prank(BORROWER); + vault.supplyCollateral(1_000_000); + vm.prank(BORROWER); + vault.borrowUsdc(500_000_000, BORROWER); + + vault.withdrawLenderUsdc(address(this), 4_500_000_000); + assertEq(vault.lenderUsdcAvailable(), 0, "available bucket withdrawn"); + + vm.expectRevert(bytes("insufficient lender usdc")); + vault.withdrawLenderUsdc(address(this), 1); + } + + function testPauseBlocksMutableUserFlows() public { + vault.pause(); + + vm.expectRevert(bytes("paused")); + vm.prank(BORROWER); + vault.supplyCollateral(1); + + vault.unpause(); + vm.prank(BORROWER); + vault.supplyCollateral(1); + } +}