From 8c17e57de450864545cbee801e220ce3efb666e0 Mon Sep 17 00:00:00 2001 From: TbIKoBKa Date: Fri, 20 Oct 2023 13:05:24 +0300 Subject: [PATCH 1/2] feat: primex adapter --- dexs/primex-finance/index.ts | 122 ++++++++++++ dexs/primex-finance/utils.ts | 359 +++++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+) create mode 100644 dexs/primex-finance/index.ts create mode 100644 dexs/primex-finance/utils.ts diff --git a/dexs/primex-finance/index.ts b/dexs/primex-finance/index.ts new file mode 100644 index 0000000000..be73abdd72 --- /dev/null +++ b/dexs/primex-finance/index.ts @@ -0,0 +1,122 @@ +import * as sdk from "@defillama/sdk"; +import { FetchResultVolume, SimpleAdapter } from "../../adapters/types" +import { getBlock } from "../../helpers/getBlock"; +import { ethers } from "ethers"; +import { getPrices } from "../../utils/prices"; +import { config, abi, topics } from "./utils"; + + +const fetch = (chain: string) => async (timestamp: number): Promise => { + const { swapManager, positionManager, tokens } = config[chain]; + + const logsConfig = [ + { + target: swapManager, + topics: [topics.swap] + }, + { + target: positionManager, + topics: [topics.openPosition] + }, + { + target: positionManager, + topics: [topics.closePosition] + }, + { + target: positionManager, + topics: [topics.partiallyClosePosition] + }, + ] + + const contractInterface = new ethers.utils.Interface(abi) + + const fromTimestamp = timestamp - 60 * 60 * 24 + const toTimestamp = timestamp + try { + const fromBlock = (await getBlock(fromTimestamp, chain, {})); + const toBlock = (await getBlock(toTimestamp, chain, {})); + + const [swapLogs, openPositionLogs, closePositionLogs, partiallyClosePositionLogs] = (await Promise.all(logsConfig.map(({ target, topics }) => { + return sdk.api.util.getLogs({ + target, + topic: '', + toBlock: toBlock, + fromBlock: fromBlock, + keys: [], + chain, + topics + }) + }))).map(r => r.output as ethers.providers.Log[]) + + const priceKeys = tokens.map((t) => `${chain}:${t.toLowerCase()}`) + const prices = await getPrices(priceKeys, timestamp); + + const swapVolumeUSD: number = swapLogs + .map((log: ethers.providers.Log) => { + const parsedLog = contractInterface.parseLog(log); + const amountSold = Number(parsedLog.args.amountSold._hex); + const tokenA = parsedLog.args.tokenA; + const priceA = prices[`${chain}:${tokenA.toLowerCase()}`]?.price || 0; + const decimalsA = prices[`${chain}:${tokenA.toLowerCase()}`]?.decimals || 0; + return (amountSold / 10 ** decimalsA) * priceA; + }) + .reduce((a: number, b: number) => a + b, 0) + + const openPositionVolumeUSD: number = openPositionLogs + .map((log: ethers.providers.Log) => { + const parsedLog = contractInterface.parseLog(log); + const soldAsset = parsedLog.args.position.soldAsset; + const priceSoldAsset = prices[`${chain}:${soldAsset.toLowerCase()}`]?.price || 0; + const decimalsSoldAsset = prices[`${chain}:${soldAsset.toLowerCase()}`]?.decimals || 0; + const depositAmountInSoldAsset = Number(parsedLog.args.position.depositAmountInSoldAsset._hex) / 10 ** decimalsSoldAsset; + const leverage = Number(parsedLog.args.leverage) / 10 ** 18 + return depositAmountInSoldAsset * leverage * priceSoldAsset; + }) + .reduce((a: number, b: number) => a + b, 0) + + const closePositionVolumeUSD: number = closePositionLogs + .map((log: ethers.providers.Log) => { + const parsedLog = contractInterface.parseLog(log); + const soldAsset = parsedLog.args.soldAsset; + const priceSoldAsset = prices[`${chain}:${soldAsset.toLowerCase()}`]?.price || 0; + const decimalsSoldAsset = prices[`${chain}:${soldAsset.toLowerCase()}`]?.decimals || 0; + const amountOut = Number(parsedLog.args.amountOut._hex) / 10 ** decimalsSoldAsset; + return amountOut * priceSoldAsset; + }) + .reduce((a: number, b: number) => a + b, 0) + + const partiallyClosePositionVolumeUSD: number = partiallyClosePositionLogs + .map((log: ethers.providers.Log) => { + const parsedLog = contractInterface.parseLog(log); + const soldAsset = parsedLog.args.soldAsset; + const priceSoldAsset = prices[`${chain}:${soldAsset.toLowerCase()}`]?.price || 0; + const decimalsSoldAsset = prices[`${chain}:${soldAsset.toLowerCase()}`]?.decimals || 0; + const amountOut = Number(parsedLog.args.amountOut._hex) / 10 ** decimalsSoldAsset; + return amountOut * priceSoldAsset; + }) + .reduce((a: number, b: number) => a + b, 0) + + const dailyVolume = swapVolumeUSD + openPositionVolumeUSD + closePositionVolumeUSD + partiallyClosePositionVolumeUSD + + return { + dailyVolume: `${dailyVolume}`, + timestamp + } + } catch(e) { + console.error(e) + throw e; + } + +} +const adapters: SimpleAdapter = { + adapter: Object.keys(config).reduce((acc, chain) => { + return { + ...acc, + [chain]: { + fetch: fetch(chain), + start: async () => config[chain].start, + } + } + }, {}) +} +export default adapters; diff --git a/dexs/primex-finance/utils.ts b/dexs/primex-finance/utils.ts new file mode 100644 index 0000000000..087f062b34 --- /dev/null +++ b/dexs/primex-finance/utils.ts @@ -0,0 +1,359 @@ +import { CHAIN } from "../../helpers/chains"; + +interface ChainConfig { + swapManager: string; + positionManager: string; + start: number; + tokens: string[] +} + +const config: { [chain: string]: ChainConfig } = { + [CHAIN.POLYGON]: { + swapManager: '0x0AaDC2Eae6963ED983d85cbF088b0c294f4c26ff', + positionManager: '0x02bcaA4633E466d151b34112608f60A82a4F6035', + start: 1697673600, + tokens: [ + '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619', + '0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6', + '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', + '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', + '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + ] + } +} + +const topics = { + swap: '0x5fcf6637f014854f918b233372226c5492e6a5157e517674a8588675550c40c6', + openPosition: '0x3f505465ce78d219c28bcf9bed881a651c4800d1161454b0d5c93225196e7b8e', + partiallyClosePosition: '0xda47f84a849dfb28125ae28a0bf305b75e72bff27796fc4bca36e2f848b0a0e6', + closePosition: '0x4a06c6510972c5a49ff5582d7d8e59f20228038c8cb9ea05d78f02ac7ee40662' +} + +const abi = [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountSold", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountBought", + "type": "uint256" + } + ], + "name": "SpotSwap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "positionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "openedBy", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "scaledDebtAmount", + "type": "uint256" + }, + { + "internalType": "contract IBucket", + "name": "bucket", + "type": "address" + }, + { + "internalType": "address", + "name": "soldAsset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "depositAmountInSoldAsset", + "type": "uint256" + }, + { + "internalType": "address", + "name": "positionAsset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "positionAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "internalType": "uint256", + "name": "openBorrowIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "createdAt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "updatedConditionsAt", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "extraParams", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct PositionLibrary.Position", + "name": "position", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "address", + "name": "feeToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "protocolFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "entryPrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "leverage", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "managerType", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct LimitOrderLibrary.Condition[]", + "name": "closeConditions", + "type": "tuple[]" + } + ], + "name": "OpenPosition", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "positionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "closedBy", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "bucketAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "soldAsset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "positionAsset", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "decreasePositionAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "profit", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "positionDebt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum PositionLibrary.CloseReason", + "name": "reason", + "type": "uint8" + } + ], + "name": "ClosePosition", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "positionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "bucketAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "soldAsset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "positionAsset", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "decreasePositionAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "depositedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "scaledDebtAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "profit", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "positionDebt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "name": "PartialClosePosition", + "type": "event" + } +] + +export { config, topics, abi } \ No newline at end of file From e4c1af056a8abf259f4dddd09eb306ec17687c8a Mon Sep 17 00:00:00 2001 From: TbIKoBKa Date: Fri, 20 Oct 2023 14:19:51 +0300 Subject: [PATCH 2/2] feat: update start date --- dexs/primex-finance/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dexs/primex-finance/utils.ts b/dexs/primex-finance/utils.ts index 087f062b34..88736214c7 100644 --- a/dexs/primex-finance/utils.ts +++ b/dexs/primex-finance/utils.ts @@ -11,7 +11,7 @@ const config: { [chain: string]: ChainConfig } = { [CHAIN.POLYGON]: { swapManager: '0x0AaDC2Eae6963ED983d85cbF088b0c294f4c26ff', positionManager: '0x02bcaA4633E466d151b34112608f60A82a4F6035', - start: 1697673600, + start: 1697587200, tokens: [ '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619', '0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6',