From 82248cc4b9481b41e451a7dc6b18ceb95c1c4753 Mon Sep 17 00:00:00 2001 From: James Russell Orola Date: Mon, 6 Nov 2023 15:28:44 +0800 Subject: [PATCH 1/7] feat: added FXPoolDeployer --- abis/FXPoolDeployer.json | 694 +++++++++++++++++++++++++++++++++++++++ assets/mainnet.json | 6 + manifest.template.yaml | 31 ++ networks.yaml | 9 + 4 files changed, 740 insertions(+) create mode 100644 abis/FXPoolDeployer.json diff --git a/abis/FXPoolDeployer.json b/abis/FXPoolDeployer.json new file mode 100644 index 00000000..28bdfb43 --- /dev/null +++ b/abis/FXPoolDeployer.json @@ -0,0 +1,694 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "oracleAddress", + "type": "address" + } + ], + "name": "ApproveBaseOracle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "assimilatorAddress", + "type": "address" + } + ], + "name": "BaseAssimilatorTemplateSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "oracleAddress", + "type": "address" + } + ], + "name": "DisapproveBaseOracle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "collectorAddress", + "type": "address" + } + ], + "name": "FXPoolCollectorSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "ownerAddress", + "type": "address" + } + ], + "name": "FXPoolOwnerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "assimilatorAddress", + "type": "address" + } + ], + "name": "NewBaseAssimilator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "fxpool", + "type": "address" + } + ], + "name": "NewFXPool", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "assimilatorAddress", + "type": "address" + } + ], + "name": "QuoteAssimilatorSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "minProtocolPercentFee", + "type": "uint256" + } + ], + "name": "SetMinProtocolPercentFee", + "type": "event" + }, + { + "inputs": [], + "name": "BASE_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "LP_MINTED_ROUNDING_ERR_THRESHOLD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_PERCENT_FEE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "QUOTE_WEIGHT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_baseOracle", + "type": "address" + } + ], + "name": "adminApproveBaseOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_baseOracle", + "type": "address" + } + ], + "name": "adminDisapproveBaseOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_a", + "type": "address" + } + ], + "name": "adminSetFxpoolCollector", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_a", + "type": "address" + } + ], + "name": "adminSetFxpoolOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_minPercentProtocolFee", + "type": "uint256" + } + ], + "name": "adminSetMinProtocolPercentFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_quoteAssim", + "type": "address" + } + ], + "name": "adminSetQuoteAssimilator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_baseAssim", + "type": "address" + } + ], + "name": "adminSetbaseAssimilatorTemplate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "baseAssimilatorTemplate", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "baseAssimilators", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "baseOraclesWhitelist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fxpoolCollector", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fxpoolOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_fxpoolAddr", + "type": "address" + } + ], + "name": "getFXPoolDetails", + "outputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "address", + "name": "baseToken", + "type": "address" + }, + { + "internalType": "address", + "name": "baseOracle", + "type": "address" + }, + { + "internalType": "uint256", + "name": "protocolPercentFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "alpha", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "beta", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "delta", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epsilon", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lambda", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_vault", + "type": "address" + }, + { + "internalType": "address", + "name": "_quoteToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_quoteAssimilator", + "type": "address" + }, + { + "internalType": "address", + "name": "_baseAssimilatorTemplate", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_baseToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_baseOracle", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_initialDepositInNumeraire", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_params", + "type": "bytes" + } + ], + "name": "newFXPool", + "outputs": [ + { + "internalType": "bytes32", + "name": "balancerPoolId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "fxpoolAddr", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "poolsData", + "outputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "poolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "baseAssimilatorTemplate", + "type": "address" + }, + { + "internalType": "bool", + "name": "exists", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "quoteAssimilator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "quoteToken", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vault", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_initialDepositInNumeraire", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_baseToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_baseOracle", + "type": "address" + } + ], + "name": "viewDepositNoLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "expectedShares", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "baseTokenAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quoteTokenAmount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/assets/mainnet.json b/assets/mainnet.json index 8646d4b4..b2c8bfcb 100644 --- a/assets/mainnet.json +++ b/assets/mainnet.json @@ -119,6 +119,12 @@ "assetSymbol": "EURS", "aggregator": "0x02F878A94a1AE1B15705aCD65b5519A46fe3517e", "aggregatorSymbol": "EUR/USD" + }, + { + "asset": "0x86B4dBE5D203e634a12364C0e428fa242A3FbA98", + "assetSymbol": "GBPT", + "aggregator": "0x568B8FD03992F56bF240958D22f5a6fcf7Bd850b", + "aggregatorSymbol": "GBP/USD" } ] } diff --git a/manifest.template.yaml b/manifest.template.yaml index da155e63..d98a9dcd 100644 --- a/manifest.template.yaml +++ b/manifest.template.yaml @@ -1535,6 +1535,37 @@ dataSources: - event: NewFXPool(indexed address,indexed bytes32,indexed address) handler: handleNewFXPool {{/if}} + {{#if FXPoolDeployer}} + - kind: ethereum/contract + name: FXPoolDeployer + network: {{network}} + source: + address: '{{FXPoolDeployer.address}}' + abi: FXPoolDeployer + startBlock: {{FXPoolDeployer.startBlock}} + mapping: + kind: ethereum/events + apiVersion: 0.0.5 + language: wasm/assemblyscript + file: ./src/mappings/poolFactory.ts + entities: + - Balancer + - Pool + abis: + - name: Vault + file: ./abis/Vault.json + - name: ERC20 + file: ./abis/ERC20.json + - name: WeightedPool + file: ./abis/WeightedPool.json + - name: FXPool + file: ./abis/FXPool.json + - name: FXPoolDeployer + file: ./abis/FXPoolDeployer.json + eventHandlers: + - event: NewFXPool(indexed address,indexed bytes32,indexed address) + handler: handleNewFXPool + {{/if}} {{#if ProtocolIdRegistry}} - kind: ethereum/contract name: ProtocolIdRegistry diff --git a/networks.yaml b/networks.yaml index f4611fc1..13d3f71c 100644 --- a/networks.yaml +++ b/networks.yaml @@ -120,6 +120,9 @@ mainnet: FXPoolFactory: address: "0x81fE9e5B28dA92aE949b705DfDB225f7a7cc5134" startBlock: 15981805 + FXPoolDeployer: + address: "0xfb23Bc0D2629268442CD6521CF4170698967105f" + startBlock: 18469425 ProtocolIdRegistry: address: "0xc3ccacE87f6d3A81724075ADcb5ddd85a8A1bB68" startBlock: 16719996 @@ -339,6 +342,9 @@ polygon: FXPoolFactory: address: "0x627D759314D5c4007b461A74eBaFA7EBC5dFeD71" startBlock: 32054793 + FXPoolDeployer: + address: "0xF169c1Ae8De24Da43a3dC5c5F05De412b4848bD3" + startBlock: 49368321 ProtocolIdRegistry: address: "0xa523f47A933D5020b23629dDf689695AA94612Dc" startBlock: 39769528 @@ -658,6 +664,9 @@ avalanche: FXPoolFactory: address: "0x81fE9e5B28dA92aE949b705DfDB225f7a7cc5134" startBlock: 32585313 + FXPoolDeployer: + address: "0x4042dC4110Ea9500338737605A60065c3de152C6" + startBlock: 37150792 basegoerli: network: base-testnet Vault: From a4f8e96798e158a54363708bb53eb4c95d7f7a08 Mon Sep 17 00:00:00 2001 From: James Russell Orola Date: Mon, 6 Nov 2023 15:39:52 +0800 Subject: [PATCH 2/7] feat: regenerated assets.ts for mainnet --- src/mappings/helpers/assets.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mappings/helpers/assets.ts b/src/mappings/helpers/assets.ts index 45891304..69e53586 100644 --- a/src/mappings/helpers/assets.ts +++ b/src/mappings/helpers/assets.ts @@ -59,5 +59,9 @@ export const assets: Assets = { Address.fromString('0xdB25f211AB05b1c97D595516F45794528a807ad8'), // EURS Address.fromString('0x02F878A94a1AE1B15705aCD65b5519A46fe3517e'), // EUR/USD ], + [ + Address.fromString('0x86B4dBE5D203e634a12364C0e428fa242A3FbA98'), // GBPT + Address.fromString('0x568B8FD03992F56bF240958D22f5a6fcf7Bd850b'), // GBP/USD + ], ], }; From 5c158449b3ef02c81d2775c15cd26c8de9b7999d Mon Sep 17 00:00:00 2001 From: James Russell Orola Date: Tue, 7 Nov 2023 14:15:02 +0800 Subject: [PATCH 3/7] feat: fetch aggregator address dynamically --- abis/Assimilator.json | 15 ++ abis/ChainlinkPriceFeed.json | 323 +++++++++++++++++++++++++++++++++++ manifest.template.yaml | 12 +- src/mappings/poolFactory.ts | 49 +++++- 4 files changed, 389 insertions(+), 10 deletions(-) create mode 100644 abis/Assimilator.json create mode 100644 abis/ChainlinkPriceFeed.json diff --git a/abis/Assimilator.json b/abis/Assimilator.json new file mode 100644 index 00000000..58f0c44f --- /dev/null +++ b/abis/Assimilator.json @@ -0,0 +1,15 @@ +[ + { + "inputs": [], + "name": "oracle", + "outputs": [ + { + "internalType": "contract IOracle", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abis/ChainlinkPriceFeed.json b/abis/ChainlinkPriceFeed.json new file mode 100644 index 00000000..5b73ffa3 --- /dev/null +++ b/abis/ChainlinkPriceFeed.json @@ -0,0 +1,323 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_aggregator", "type": "address" }, + { + "internalType": "address", + "name": "_accessController", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "int256", + "name": "current", + "type": "int256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "roundId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "updatedAt", + "type": "uint256" + } + ], + "name": "AnswerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "roundId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "startedBy", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "startedAt", + "type": "uint256" + } + ], + "name": "NewRound", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "OwnershipTransferRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "accessController", + "outputs": [ + { + "internalType": "contract AccessControllerInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "aggregator", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_aggregator", "type": "address" } + ], + "name": "confirmAggregator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "description", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_roundId", "type": "uint256" } + ], + "name": "getAnswer", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint80", "name": "_roundId", "type": "uint80" } + ], + "name": "getRoundData", + "outputs": [ + { "internalType": "uint80", "name": "roundId", "type": "uint80" }, + { "internalType": "int256", "name": "answer", "type": "int256" }, + { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, + { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, + { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_roundId", "type": "uint256" } + ], + "name": "getTimestamp", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "latestAnswer", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "latestRound", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "latestRoundData", + "outputs": [ + { "internalType": "uint80", "name": "roundId", "type": "uint80" }, + { "internalType": "int256", "name": "answer", "type": "int256" }, + { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, + { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, + { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "latestTimestamp", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "name": "phaseAggregators", + "outputs": [ + { + "internalType": "contract AggregatorV2V3Interface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "phaseId", + "outputs": [{ "internalType": "uint16", "name": "", "type": "uint16" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_aggregator", "type": "address" } + ], + "name": "proposeAggregator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "proposedAggregator", + "outputs": [ + { + "internalType": "contract AggregatorV2V3Interface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint80", "name": "_roundId", "type": "uint80" } + ], + "name": "proposedGetRoundData", + "outputs": [ + { "internalType": "uint80", "name": "roundId", "type": "uint80" }, + { "internalType": "int256", "name": "answer", "type": "int256" }, + { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, + { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, + { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proposedLatestRoundData", + "outputs": [ + { "internalType": "uint80", "name": "roundId", "type": "uint80" }, + { "internalType": "int256", "name": "answer", "type": "int256" }, + { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, + { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, + { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_accessController", + "type": "address" + } + ], + "name": "setController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_to", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/manifest.template.yaml b/manifest.template.yaml index d98a9dcd..7bdbc3e3 100644 --- a/manifest.template.yaml +++ b/manifest.template.yaml @@ -1531,9 +1531,13 @@ dataSources: file: ./abis/FXPool.json - name: FXPoolFactory file: ./abis/FXPoolFactory.json + - name: Assimilator + file: ./abis/Assimilator.json + - name: ChainlinkPriceFeed + file: ./abis/ChainlinkPriceFeed.json eventHandlers: - event: NewFXPool(indexed address,indexed bytes32,indexed address) - handler: handleNewFXPool + handler: handleNewFXPoolV1 {{/if}} {{#if FXPoolDeployer}} - kind: ethereum/contract @@ -1562,9 +1566,13 @@ dataSources: file: ./abis/FXPool.json - name: FXPoolDeployer file: ./abis/FXPoolDeployer.json + - name: Assimilator + file: ./abis/Assimilator.json + - name: ChainlinkPriceFeed + file: ./abis/ChainlinkPriceFeed.json eventHandlers: - event: NewFXPool(indexed address,indexed bytes32,indexed address) - handler: handleNewFXPool + handler: handleNewFXPoolV2 {{/if}} {{#if ProtocolIdRegistry}} - kind: ethereum/contract diff --git a/src/mappings/poolFactory.ts b/src/mappings/poolFactory.ts index 12522ee8..eebd5a1d 100644 --- a/src/mappings/poolFactory.ts +++ b/src/mappings/poolFactory.ts @@ -52,6 +52,9 @@ import { LinearPool } from '../types/templates/LinearPool/LinearPool'; import { Gyro2Pool } from '../types/templates/Gyro2Pool/Gyro2Pool'; import { Gyro3Pool } from '../types/templates/Gyro3Pool/Gyro3Pool'; import { GyroEPool } from '../types/templates/GyroEPool/GyroEPool'; +import { FXPool } from '../types/templates/FXPool/FXPool'; +import { Assimilator } from '../types/FXPoolDeployer/Assimilator'; +import { ChainlinkPriceFeed } from '../types/FXPoolDeployer/ChainlinkPriceFeed'; import { Transfer } from '../types/Vault/ERC20'; import { handleTransfer } from './poolController'; import { ComposableStablePool } from '../types/ComposableStablePoolFactory/ComposableStablePool'; @@ -568,9 +571,17 @@ export function handleNewGyroEV2Pool(event: PoolCreated): void { createGyroEPool(event, 2); } -export function handleNewFXPool(event: ethereum.Event): void { +export function handleNewFXPoolV1(event: ethereum.Event): void { + return handleNewFXPool(event, false); +} + +export function handleNewFXPoolV2(event: ethereum.Event): void { + return handleNewFXPool(event, true); +} + +function handleNewFXPool(event: ethereum.Event, permissionless: boolean): void { /** - * FXPoolFactory emits a custom NewFXPool event with the following params: + * FXPoolFactory/FXPoolDeployer emits a custom NewFXPool event with the following params: * event.parameters[0] = caller * event.parameters[1] = id (vault poolId) * event.parameters[2] = fxpool (pool address) @@ -607,14 +618,36 @@ export function handleNewFXPool(event: ethereum.Event): void { // Create templates for each token Offchain Aggregator let tokensAddresses = changetype(tokens); - tokensAddresses.forEach((tokenAddress) => { - for (let i = 0; i < FX_ASSET_AGGREGATORS.length; i++) { - if (FX_ASSET_AGGREGATORS[i][0] == tokenAddress) { - OffchainAggregator.create(FX_ASSET_AGGREGATORS[i][1]); - break; + + if (!permissionless) { + // For FXPoolFactory, use hardcoded aggregator addresses + tokensAddresses.forEach((tokenAddress) => { + for (let i = 0; i < FX_ASSET_AGGREGATORS.length; i++) { + if (FX_ASSET_AGGREGATORS[i][0] == tokenAddress) { + OffchainAggregator.create(FX_ASSET_AGGREGATORS[i][1]); + break; + } + } + }); + } else { + // For FXPoolDeployer (permissionless), fetch the aggregator address dynamically + let poolContract = FXPool.bind(poolAddress); + for (let i = 0; i < tokensAddresses.length; i++) { + let tokenAddress = tokensAddresses[i]; + let assimCall = poolContract.try_assimilator(tokenAddress); + if (!assimCall.reverted) { + let assimContract = Assimilator.bind(assimCall.value); + let oracleCall = assimContract.try_oracle(); + if (!oracleCall.reverted) { + let oracleContract = ChainlinkPriceFeed.bind(oracleCall.value); + let aggregatorCall = oracleContract.try_aggregator(); + if (!aggregatorCall.reverted) { + OffchainAggregator.create(aggregatorCall.value); + } + } } } - }); + } } function findOrInitializeVault(): Balancer { From e6e60e9e53c2dd53bc7723296984291c6aaa0c93 Mon Sep 17 00:00:00 2001 From: James Russell Orola Date: Tue, 7 Nov 2023 14:17:30 +0800 Subject: [PATCH 4/7] feat: reverted adding of GBPT oracle aggregator address --- assets/mainnet.json | 6 ------ src/mappings/helpers/assets.ts | 4 ---- 2 files changed, 10 deletions(-) diff --git a/assets/mainnet.json b/assets/mainnet.json index b2c8bfcb..8646d4b4 100644 --- a/assets/mainnet.json +++ b/assets/mainnet.json @@ -119,12 +119,6 @@ "assetSymbol": "EURS", "aggregator": "0x02F878A94a1AE1B15705aCD65b5519A46fe3517e", "aggregatorSymbol": "EUR/USD" - }, - { - "asset": "0x86B4dBE5D203e634a12364C0e428fa242A3FbA98", - "assetSymbol": "GBPT", - "aggregator": "0x568B8FD03992F56bF240958D22f5a6fcf7Bd850b", - "aggregatorSymbol": "GBP/USD" } ] } diff --git a/src/mappings/helpers/assets.ts b/src/mappings/helpers/assets.ts index 69e53586..45891304 100644 --- a/src/mappings/helpers/assets.ts +++ b/src/mappings/helpers/assets.ts @@ -59,9 +59,5 @@ export const assets: Assets = { Address.fromString('0xdB25f211AB05b1c97D595516F45794528a807ad8'), // EURS Address.fromString('0x02F878A94a1AE1B15705aCD65b5519A46fe3517e'), // EUR/USD ], - [ - Address.fromString('0x86B4dBE5D203e634a12364C0e428fa242A3FbA98'), // GBPT - Address.fromString('0x568B8FD03992F56bF240958D22f5a6fcf7Bd850b'), // GBP/USD - ], ], }; From a084a1ceec40e3a087f4cb371d1e0518896970db Mon Sep 17 00:00:00 2001 From: James Russell Orola Date: Thu, 9 Nov 2023 10:19:01 +0800 Subject: [PATCH 5/7] feat: store oracle-tokens map in a new FXOracle entity --- assets/avalanche.json | 2 +- schema.graphql | 5 +++++ src/mappings/helpers/misc.ts | 11 ++++++++++ src/mappings/poolFactory.ts | 42 +++++++++++++++++++++++++----------- src/mappings/pricing.ts | 24 +++++++++++++++------ 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/assets/avalanche.json b/assets/avalanche.json index 4c1203b6..1d7f989f 100644 --- a/assets/avalanche.json +++ b/assets/avalanche.json @@ -61,7 +61,7 @@ { "asset": "0x228a48df6819CCc2eCa01e2192ebAFfFdAD56c19", "assetSymbol": "VCHF", - "aggregator": "0xA418573AB5226711c8564Eeb449c3618ABFaf677", + "aggregator": "0x3D22B2c729A952402d898D1041F5E4828FF3695c", "aggregatorSymbol": "CHF/USD" } ] diff --git a/schema.graphql b/schema.graphql index af4c4bd9..6c2fd32b 100644 --- a/schema.graphql +++ b/schema.graphql @@ -397,3 +397,8 @@ type ProtocolIdData @entity { id: ID! name: String! } + +type FXOracle @entity { + id: ID! # FX oracle aggregator address + tokens: [Bytes!]! # token addresses using this oracle +} \ No newline at end of file diff --git a/src/mappings/helpers/misc.ts b/src/mappings/helpers/misc.ts index a5ce0225..0e121a76 100644 --- a/src/mappings/helpers/misc.ts +++ b/src/mappings/helpers/misc.ts @@ -12,6 +12,7 @@ import { TradePairSnapshot, BalancerSnapshot, Balancer, + FXOracle } from '../../types/schema'; import { ERC20 } from '../../types/Vault/ERC20'; import { WeightedPool } from '../../types/Vault/WeightedPool'; @@ -467,3 +468,13 @@ export function getProtocolFeeCollector(): Address | null { return feesCollector.value; } + +export function getFXOracle(oracleAddress: Address): FXOracle { + let oracle = FXOracle.load(oracleAddress.toHexString()); + if (oracle == null) { + oracle = new FXOracle(oracleAddress.toHexString()); + oracle.tokens = []; + oracle.save(); + } + return oracle; +} diff --git a/src/mappings/poolFactory.ts b/src/mappings/poolFactory.ts index eebd5a1d..04c538d7 100644 --- a/src/mappings/poolFactory.ts +++ b/src/mappings/poolFactory.ts @@ -17,10 +17,11 @@ import { bytesToAddress, getProtocolFeeCollector, getToken, + getFXOracle, } from './helpers/misc'; import { updatePoolWeights } from './helpers/weighted'; -import { BigInt, Address, Bytes, ethereum } from '@graphprotocol/graph-ts'; +import { BigInt, Address, Bytes, ethereum, log } from '@graphprotocol/graph-ts'; import { PoolCreated } from '../types/WeightedPoolFactory/WeightedPoolFactory'; import { AaveLinearPoolCreated } from '../types/AaveLinearPoolV3Factory/AaveLinearPoolV3Factory'; import { ProtocolIdRegistered } from '../types/ProtocolIdRegistry/ProtocolIdRegistry'; @@ -632,20 +633,37 @@ function handleNewFXPool(event: ethereum.Event, permissionless: boolean): void { } else { // For FXPoolDeployer (permissionless), fetch the aggregator address dynamically let poolContract = FXPool.bind(poolAddress); + for (let i = 0; i < tokensAddresses.length; i++) { let tokenAddress = tokensAddresses[i]; let assimCall = poolContract.try_assimilator(tokenAddress); - if (!assimCall.reverted) { - let assimContract = Assimilator.bind(assimCall.value); - let oracleCall = assimContract.try_oracle(); - if (!oracleCall.reverted) { - let oracleContract = ChainlinkPriceFeed.bind(oracleCall.value); - let aggregatorCall = oracleContract.try_aggregator(); - if (!aggregatorCall.reverted) { - OffchainAggregator.create(aggregatorCall.value); - } - } - } + log.warning('[JAMES-DEBUG] Token assim: {} = {}', [tokenAddress.toHexString(), assimCall.value.toHexString()]); + if (assimCall.reverted) continue; + + let assimContract = Assimilator.bind(assimCall.value); + let oracleCall = assimContract.try_oracle(); + log.warning('[JAMES-DEBUG] Assim oracle: {} = {}', [ + assimCall.value.toHexString(), + oracleCall.value.toHexString(), + ]); + if (oracleCall.reverted) continue; + + let oracleContract = ChainlinkPriceFeed.bind(oracleCall.value); + let aggregatorCall = oracleContract.try_aggregator(); + log.warning('[JAMES-DEBUG] Oracle agregator: {} = {}', [ + oracleCall.value.toHexString(), + aggregatorCall.value.toHexString(), + ]); + if (aggregatorCall.reverted) continue; + + // Create OffchainAggregator template + let aggregatorAddress = aggregatorCall.value; + OffchainAggregator.create(aggregatorAddress); + + // Update FXOracle supported tokens + let oracle = getFXOracle(aggregatorAddress); + oracle.tokens.push(tokenAddress); // @todo: add if not exists + oracle.save(); } } } diff --git a/src/mappings/pricing.ts b/src/mappings/pricing.ts index 0c1a0f0c..3b708680 100644 --- a/src/mappings/pricing.ts +++ b/src/mappings/pricing.ts @@ -1,5 +1,5 @@ import { Address, Bytes, BigInt, BigDecimal, log, dataSource } from '@graphprotocol/graph-ts'; -import { Pool, TokenPrice, Balancer, PoolHistoricalLiquidity, LatestPrice, Token } from '../types/schema'; +import { Pool, TokenPrice, Balancer, PoolHistoricalLiquidity, LatestPrice, Token, FXOracle } from '../types/schema'; import { ZERO_BD, PRICING_ASSETS, @@ -371,14 +371,28 @@ export function setWrappedTokenPrice(pool: Pool, poolId: string, block_number: B } export function handleAnswerUpdated(event: AnswerUpdated): void { - let tokenAddress = ZERO_ADDRESS; const aggregatorAddress = event.address; + const answer = event.params.current; + const tokenAddressesToUpdate: Address[] = []; + // Check if the aggregator is under FX_ASSET_AGGREGATORS first (FXPoolFactory version) for (let i = 0; i < FX_ASSET_AGGREGATORS.length; i++) { - if (aggregatorAddress != FX_ASSET_AGGREGATORS[i][1]) continue; + if (aggregatorAddress == FX_ASSET_AGGREGATORS[i][1]) { + tokenAddressesToUpdate.push(FX_ASSET_AGGREGATORS[i][0]); + } + } - tokenAddress = FX_ASSET_AGGREGATORS[i][0]; + // Also check if aggregator exists from FXOracle entity (FXPoolDeployer version) + let oracle = FXOracle.load(aggregatorAddress.toHexString()); + if (oracle) { + for (let i = 0; i < oracle.tokens.length; i++) { + tokenAddressesToUpdate.push(Address.fromBytes(oracle.tokens[i])); + } + } + // Update all tokens using this aggregator + for (let i = 0; i < tokenAddressesToUpdate.length; i++) { + const tokenAddress = tokenAddressesToUpdate[i]; const token = Token.load(tokenAddress.toHexString()); if (token == null) { log.warning('Token with address {} not found', [tokenAddress.toHexString()]); @@ -390,8 +404,6 @@ export function handleAnswerUpdated(event: AnswerUpdated): void { token.fxOracleDecimals = 8; // @todo: get decimals on-chain } - const answer = event.params.current; - if (tokenAddress == Address.fromString('0xc8bb8eda94931ca2f20ef43ea7dbd58e68400400')) { // XAU-USD oracle returns an answer with price unit of "USD per troy ounce" // For VNXAU however, we wanna use a price unit of "USD per gram" From f129d639e10f347a2ec5cc5f6c536177085c0aec Mon Sep 17 00:00:00 2001 From: James Russell Orola Date: Thu, 9 Nov 2023 17:41:51 +0800 Subject: [PATCH 6/7] feat: add duplicate check --- src/mappings/poolFactory.ts | 9 +++++++-- src/mappings/pricing.ts | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/mappings/poolFactory.ts b/src/mappings/poolFactory.ts index 04c538d7..bb29864b 100644 --- a/src/mappings/poolFactory.ts +++ b/src/mappings/poolFactory.ts @@ -618,7 +618,7 @@ function handleNewFXPool(event: ethereum.Event, permissionless: boolean): void { FXPoolTemplate.create(poolAddress); // Create templates for each token Offchain Aggregator - let tokensAddresses = changetype(tokens); + let tokensAddresses: Address[] = changetype(tokens); if (!permissionless) { // For FXPoolFactory, use hardcoded aggregator addresses @@ -662,7 +662,12 @@ function handleNewFXPool(event: ethereum.Event, permissionless: boolean): void { // Update FXOracle supported tokens let oracle = getFXOracle(aggregatorAddress); - oracle.tokens.push(tokenAddress); // @todo: add if not exists + let tokenAddresses = oracle.tokens; + const tokenExists = tokenAddresses.includes(tokenAddress); + if (!tokenExists) { + tokenAddresses.push(tokenAddress); + } + oracle.tokens = tokenAddresses; oracle.save(); } } diff --git a/src/mappings/pricing.ts b/src/mappings/pricing.ts index 3b708680..1305c2b1 100644 --- a/src/mappings/pricing.ts +++ b/src/mappings/pricing.ts @@ -386,7 +386,11 @@ export function handleAnswerUpdated(event: AnswerUpdated): void { let oracle = FXOracle.load(aggregatorAddress.toHexString()); if (oracle) { for (let i = 0; i < oracle.tokens.length; i++) { - tokenAddressesToUpdate.push(Address.fromBytes(oracle.tokens[i])); + const tokenAddress = Address.fromBytes(oracle.tokens[i]); + const tokenExists = tokenAddressesToUpdate.includes(tokenAddress); + if (!tokenExists) { + tokenAddressesToUpdate.push(tokenAddress); + } } } From 0fcd112de212febad88bd7c5854babdff7b9b910 Mon Sep 17 00:00:00 2001 From: James Russell Orola Date: Thu, 9 Nov 2023 17:46:33 +0800 Subject: [PATCH 7/7] refactor: fix lint issues + removed debug logs --- src/mappings/helpers/misc.ts | 2 +- src/mappings/poolFactory.ts | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/mappings/helpers/misc.ts b/src/mappings/helpers/misc.ts index 0e121a76..d1bc84a6 100644 --- a/src/mappings/helpers/misc.ts +++ b/src/mappings/helpers/misc.ts @@ -12,7 +12,7 @@ import { TradePairSnapshot, BalancerSnapshot, Balancer, - FXOracle + FXOracle, } from '../../types/schema'; import { ERC20 } from '../../types/Vault/ERC20'; import { WeightedPool } from '../../types/Vault/WeightedPool'; diff --git a/src/mappings/poolFactory.ts b/src/mappings/poolFactory.ts index bb29864b..febe281a 100644 --- a/src/mappings/poolFactory.ts +++ b/src/mappings/poolFactory.ts @@ -21,7 +21,7 @@ import { } from './helpers/misc'; import { updatePoolWeights } from './helpers/weighted'; -import { BigInt, Address, Bytes, ethereum, log } from '@graphprotocol/graph-ts'; +import { BigInt, Address, Bytes, ethereum } from '@graphprotocol/graph-ts'; import { PoolCreated } from '../types/WeightedPoolFactory/WeightedPoolFactory'; import { AaveLinearPoolCreated } from '../types/AaveLinearPoolV3Factory/AaveLinearPoolV3Factory'; import { ProtocolIdRegistered } from '../types/ProtocolIdRegistry/ProtocolIdRegistry'; @@ -637,23 +637,14 @@ function handleNewFXPool(event: ethereum.Event, permissionless: boolean): void { for (let i = 0; i < tokensAddresses.length; i++) { let tokenAddress = tokensAddresses[i]; let assimCall = poolContract.try_assimilator(tokenAddress); - log.warning('[JAMES-DEBUG] Token assim: {} = {}', [tokenAddress.toHexString(), assimCall.value.toHexString()]); if (assimCall.reverted) continue; let assimContract = Assimilator.bind(assimCall.value); let oracleCall = assimContract.try_oracle(); - log.warning('[JAMES-DEBUG] Assim oracle: {} = {}', [ - assimCall.value.toHexString(), - oracleCall.value.toHexString(), - ]); if (oracleCall.reverted) continue; let oracleContract = ChainlinkPriceFeed.bind(oracleCall.value); let aggregatorCall = oracleContract.try_aggregator(); - log.warning('[JAMES-DEBUG] Oracle agregator: {} = {}', [ - oracleCall.value.toHexString(), - aggregatorCall.value.toHexString(), - ]); if (aggregatorCall.reverted) continue; // Create OffchainAggregator template