diff --git a/backend/src/abi/EtherspotChainlinkOracleAbi.ts b/backend/src/abi/EtherspotChainlinkOracleAbi.ts new file mode 100644 index 0000000..a53d6dd --- /dev/null +++ b/backend/src/abi/EtherspotChainlinkOracleAbi.ts @@ -0,0 +1,363 @@ +export default [ + { + "inputs": [ + { + "internalType": "string", + "name": "_pairName", + "type": "string" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ActiveOracle", + "type": "error" + }, + { + "inputs": [], + "name": "InactiveOracle", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceLastUpdatedAt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outdatedBy", + "type": "uint256" + } + ], + "name": "StalePriceData", + "type": "error" + }, + { + "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": [], + "name": "PriceFeedUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint80", + "name": "roundId", + "type": "uint80" + }, + { + "indexed": false, + "internalType": "int256", + "name": "answer", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "startedAt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "updatedAt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint80", + "name": "answeredInRound", + "type": "uint80" + } + ], + "name": "ReceivedPriceData", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "UpdateReceived", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "UpdateRequested", + "type": "event" + }, + { + "inputs": [], + "name": "AGE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activateOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "active", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "cachedPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "deactivateOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "fulfillPriceData", + "outputs": [], + "stateMutability": "nonpayable", + "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": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pairName", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceLastUpdatedAt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "requestPriceData", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "token", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/backend/src/routes/index.ts b/backend/src/routes/index.ts index 301f9a7..a06818c 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/index.ts @@ -12,6 +12,7 @@ import ReturnCode from "../constants/ReturnCode.js"; import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager"; import PimlicoAbi from "../abi/PimlicoAbi.js"; import PythOracleAbi from "../abi/PythOracleAbi.js"; +import EtherspotChainlinkOracleAbi from "../abi/EtherspotChainlinkOracleAbi.js"; const logger = pino({ transport: { @@ -111,7 +112,7 @@ const routes: FastifyPluginAsync = async (server) => { const validUntil = context.validUntil ? new Date(context.validUntil) : date; const validAfter = context.validAfter ? new Date(context.validAfter) : date; const hex = (Number((validUntil.valueOf() / 1000).toFixed(0)) + 600).toString(16); - const hex1 = (Number((validAfter.valueOf() / 1000).toFixed(0))).toString(16); + const hex1 = (Number((validAfter.valueOf() / 1000).toFixed(0)) - 60).toString(16); let str = '0x' let str1 = '0x' for (let i = 0; i < 14 - hex.length; i++) { @@ -415,6 +416,32 @@ export async function cronJob() { logger.error(err); } } + const customChainlinkDeploymentsbase64 = process.env.CUSTOM_CHAINLINK_DEPLOYED; + if (customChainlinkDeploymentsbase64) { + try { + const buffer = Buffer.from(customChainlinkDeploymentsbase64, 'base64'); + const customChainlinks = JSON.parse(buffer.toString()); + const customChainlinkDeployments = customChainlinks[chain] ?? []; + if (customChainlinkDeployments.includes(deployedPaymaster)) { + const coingeckoIds = process.env.COINGECKO_IDS?.split(',') ?? ['']; + const coingeckoId = coingeckoIds[customChainlinkDeployments.indexOf(deployedPaymaster)] + const response: any = await (await fetch(`${process.env.COINGECKO_API_URL}${coingeckoId}`)).json(); + const price = ethers.utils.parseUnits(response[coingeckoId].usd.toString(), 8); + if (price) { + const oracleAddress = await paymasterContract.tokenOracle(); + const oracleContract = new ethers.Contract(oracleAddress, EtherspotChainlinkOracleAbi, provider) + const data = oracleContract.interface.encodeFunctionData('fulfillPriceData', [price]) + const tx = await signer.sendTransaction({ + to: oracleAddress, + data: data, + }); + await tx.wait(); + } + } + } catch (err) { + logger.error('Err on fetching price from coingecko' + err) + } + } try { await paymasterContract.updatePrice(); logger.info('Price Updated for ' + chain);