diff --git a/pkg/source/zkera-finance/abis.go b/pkg/source/zkera-finance/abis.go new file mode 100644 index 000000000..d64aed0f1 --- /dev/null +++ b/pkg/source/zkera-finance/abis.go @@ -0,0 +1,40 @@ +package zkerafinance + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +var ( + fastPriceFeedV1ABI abi.ABI + fastPriceFeedV2ABI abi.ABI + pancakePairABI abi.ABI + priceFeedABI abi.ABI + vaultABI abi.ABI + vaultPriceFeedABI abi.ABI + erc20ABI abi.ABI +) + +func init() { + builder := []struct { + ABI *abi.ABI + data []byte + }{ + {&fastPriceFeedV1ABI, fastPriceFeedV1Json}, + {&fastPriceFeedV2ABI, fastPriceFeedV2Json}, + {&pancakePairABI, pancakePairJson}, + {&priceFeedABI, priceFeedJson}, + {&vaultABI, vaultJson}, + {&vaultPriceFeedABI, vaultPriceFeedJson}, + {&erc20ABI, erc20Json}, + } + + for _, b := range builder { + var err error + *b.ABI, err = abi.JSON(bytes.NewReader(b.data)) + if err != nil { + panic(err) + } + } +} diff --git a/pkg/source/zkera-finance/abis/ERC20.json b/pkg/source/zkera-finance/abis/ERC20.json new file mode 100644 index 000000000..3b0ab2f1a --- /dev/null +++ b/pkg/source/zkera-finance/abis/ERC20.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] \ No newline at end of file diff --git a/pkg/source/zkera-finance/abis/FastPriceFeedV1.json b/pkg/source/zkera-finance/abis/FastPriceFeedV1.json new file mode 100644 index 000000000..30ecc19e5 --- /dev/null +++ b/pkg/source/zkera-finance/abis/FastPriceFeedV1.json @@ -0,0 +1,788 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minBlockInterval", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxDeviationBasisPoints", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_fastPriceEvents", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenManager", + "type": "address" + }, + { + "internalType": "address", + "name": "_positionRouter", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "DisableFastPrice", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "EnableFastPrice", + "type": "event" + }, + { + "inputs": [], + "name": "BASIS_POINTS_DIVISOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_PRICE_DURATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PRICE_BITMASK", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PRICE_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "disableFastPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableFastPriceVoteCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "disableFastPriceVotes", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "enableFastPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "fastPriceEvents", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "favorFastPrice", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_refPrice", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_maximise", + "type": "bool" + } + ], + "name": "getPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gov", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_minAuthorizations", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "_signers", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "_updaters", + "type": "address[]" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isSigner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isSpreadEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isUpdater", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastUpdatedAt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastUpdatedBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxDeviationBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxTimeDeviation", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minAuthorizations", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minBlockInterval", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "positionRouter", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "prices", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_priceBitArray", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + } + ], + "name": "setCompactedPrices", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_fastPriceEvents", + "type": "address" + } + ], + "name": "setFastPriceEvents", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gov", + "type": "address" + } + ], + "name": "setGov", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_isSpreadEnabled", + "type": "bool" + } + ], + "name": "setIsSpreadEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_lastUpdatedAt", + "type": "uint256" + } + ], + "name": "setLastUpdatedAt", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxDeviationBasisPoints", + "type": "uint256" + } + ], + "name": "setMaxDeviationBasisPoints", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxTimeDeviation", + "type": "uint256" + } + ], + "name": "setMaxTimeDeviation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_minAuthorizations", + "type": "uint256" + } + ], + "name": "setMinAuthorizations", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_minBlockInterval", + "type": "uint256" + } + ], + "name": "setMinBlockInterval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceDuration", + "type": "uint256" + } + ], + "name": "setPriceDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_prices", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + } + ], + "name": "setPrices", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceBits", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + } + ], + "name": "setPricesWithBits", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceBits", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_endIndexForIncreasePositions", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_endIndexForDecreasePositions", + "type": "uint256" + } + ], + "name": "setPricesWithBitsAndExecute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isActive", + "type": "bool" + } + ], + "name": "setSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenManager", + "type": "address" + } + ], + "name": "setTokenManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_tokenPrecisions", + "type": "uint256[]" + } + ], + "name": "setTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isActive", + "type": "bool" + } + ], + "name": "setUpdater", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_volBasisPoints", + "type": "uint256" + } + ], + "name": "setVolBasisPoints", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "tokenManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "tokenPrecisions", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "tokens", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "volBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/pkg/source/zkera-finance/abis/FastPriceFeedV2.json b/pkg/source/zkera-finance/abis/FastPriceFeedV2.json new file mode 100644 index 000000000..27cb26319 --- /dev/null +++ b/pkg/source/zkera-finance/abis/FastPriceFeedV2.json @@ -0,0 +1,1144 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxPriceUpdateDelay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minBlockInterval", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxDeviationBasisPoints", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_fastPriceEvents", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenManager", + "type": "address" + }, + { + "internalType": "address", + "name": "_positionRouter", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "DisableFastPrice", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "EnableFastPrice", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "refPrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fastPrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cumulativeRefDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cumulativeFastDelta", + "type": "uint256" + } + ], + "name": "MaxCumulativeDeltaDiffExceeded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "refPrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fastPrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cumulativeRefDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cumulativeFastDelta", + "type": "uint256" + } + ], + "name": "PriceData", + "type": "event" + }, + { + "inputs": [], + "name": "BASIS_POINTS_DIVISOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BITMASK_32", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CUMULATIVE_DELTA_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_CUMULATIVE_FAST_DELTA", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_CUMULATIVE_REF_DELTA", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_PRICE_DURATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_REF_PRICE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PRICE_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "disableFastPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disableFastPriceVoteCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "disableFastPriceVotes", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "enableFastPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "fastPriceEvents", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "favorFastPrice", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_refPrice", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_maximise", + "type": "bool" + } + ], + "name": "getPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getPriceData", + "outputs": [ + { + "internalType": "uint256", + "name": "refPrice", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "refTime", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "cumulativeRefDelta", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "cumulativeFastDelta", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gov", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_minAuthorizations", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "_signers", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "_updaters", + "type": "address[]" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isSigner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isSpreadEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isUpdater", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastUpdatedAt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastUpdatedBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxCumulativeDeltaDiffs", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxDeviationBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxPriceUpdateDelay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxTimeDeviation", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minAuthorizations", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minBlockInterval", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "positionRouter", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "priceData", + "outputs": [ + { + "internalType": "uint160", + "name": "refPrice", + "type": "uint160" + }, + { + "internalType": "uint32", + "name": "refTime", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "cumulativeRefDelta", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "cumulativeFastDelta", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceDataInterval", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "prices", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_priceBitArray", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + } + ], + "name": "setCompactedPrices", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_fastPriceEvents", + "type": "address" + } + ], + "name": "setFastPriceEvents", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gov", + "type": "address" + } + ], + "name": "setGov", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_isSpreadEnabled", + "type": "bool" + } + ], + "name": "setIsSpreadEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_lastUpdatedAt", + "type": "uint256" + } + ], + "name": "setLastUpdatedAt", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_maxCumulativeDeltaDiffs", + "type": "uint256[]" + } + ], + "name": "setMaxCumulativeDeltaDiffs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxDeviationBasisPoints", + "type": "uint256" + } + ], + "name": "setMaxDeviationBasisPoints", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxPriceUpdateDelay", + "type": "uint256" + } + ], + "name": "setMaxPriceUpdateDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxTimeDeviation", + "type": "uint256" + } + ], + "name": "setMaxTimeDeviation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_minAuthorizations", + "type": "uint256" + } + ], + "name": "setMinAuthorizations", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_minBlockInterval", + "type": "uint256" + } + ], + "name": "setMinBlockInterval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceDataInterval", + "type": "uint256" + } + ], + "name": "setPriceDataInterval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceDuration", + "type": "uint256" + } + ], + "name": "setPriceDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_prices", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + } + ], + "name": "setPrices", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceBits", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + } + ], + "name": "setPricesWithBits", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceBits", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_timestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_endIndexForIncreasePositions", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_endIndexForDecreasePositions", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIncreasePositions", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxDecreasePositions", + "type": "uint256" + } + ], + "name": "setPricesWithBitsAndExecute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isActive", + "type": "bool" + } + ], + "name": "setSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_spreadBasisPointsIfChainError", + "type": "uint256" + } + ], + "name": "setSpreadBasisPointsIfChainError", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_spreadBasisPointsIfInactive", + "type": "uint256" + } + ], + "name": "setSpreadBasisPointsIfInactive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenManager", + "type": "address" + } + ], + "name": "setTokenManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_tokenPrecisions", + "type": "uint256[]" + } + ], + "name": "setTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isActive", + "type": "bool" + } + ], + "name": "setUpdater", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_vaultPriceFeed", + "type": "address" + } + ], + "name": "setVaultPriceFeed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "spreadBasisPointsIfChainError", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "spreadBasisPointsIfInactive", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tokenManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "tokenPrecisions", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "tokens", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaultPriceFeed", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/pkg/source/zkera-finance/abis/PancakePair.json b/pkg/source/zkera-finance/abis/PancakePair.json new file mode 100644 index 000000000..00fc4365d --- /dev/null +++ b/pkg/source/zkera-finance/abis/PancakePair.json @@ -0,0 +1,27 @@ +[ + { + "constant": true, + "inputs": [], + "name": "getReserves", + "outputs": [ + { + "internalType": "uint112", + "name": "_reserve0", + "type": "uint112" + }, + { + "internalType": "uint112", + "name": "_reserve1", + "type": "uint112" + }, + { + "internalType": "uint32", + "name": "_blockTimestampLast", + "type": "uint32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/pkg/source/zkera-finance/abis/PriceFeed.json b/pkg/source/zkera-finance/abis/PriceFeed.json new file mode 100644 index 000000000..3d8eea40a --- /dev/null +++ b/pkg/source/zkera-finance/abis/PriceFeed.json @@ -0,0 +1,146 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_pythContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_priceFeedId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_age", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "age", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gov", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "maximize", + "type": "bool" + } + ], + "name": "latestAnswer", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeedId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pyth", + "outputs": [ + { + "internalType": "contract IPyth", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_age", + "type": "uint256" + } + ], + "name": "setAge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gov", + "type": "address" + } + ], + "name": "setGov", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "priceUpdateData", + "type": "bytes[]" + } + ], + "name": "updateAnswer", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] \ No newline at end of file diff --git a/pkg/source/zkera-finance/abis/Vault.json b/pkg/source/zkera-finance/abis/Vault.json new file mode 100644 index 000000000..c16635be9 --- /dev/null +++ b/pkg/source/zkera-finance/abis/Vault.json @@ -0,0 +1,3299 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_delegatePartOne", + "type": "address" + }, + { + "internalType": "address", + "name": "_delegatePartTwo", + "type": "address" + }, + { + "internalType": "address", + "name": "_delegatePartThree", + "type": "address" + }, + { + "internalType": "contract IBlockInfo", + "name": "_blockInfo", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "usdgAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeBasisPoints", + "type": "uint256" + } + ], + "name": "BuyUSDG", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "averagePrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "entryFundingRate", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reserveAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "realisedPnl", + "type": "int256" + } + ], + "name": "ClosePosition", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeUsd", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeTokens", + "type": "uint256" + } + ], + "name": "CollectMarginFees", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeUsd", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeTokens", + "type": "uint256" + } + ], + "name": "CollectSwapFees", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DecreaseGuaranteedUsd", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DecreasePoolAmount", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "collateralToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "indexToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "sizeDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isLong", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "DecreasePosition", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DecreaseReservedAmount", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DecreaseUsdgAmount", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DirectPoolDeposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "IncreaseGuaranteedUsd", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "IncreasePoolAmount", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "collateralToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "indexToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "sizeDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isLong", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "IncreasePosition", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "IncreaseReservedAmount", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "IncreaseUsdgAmount", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "collateralToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "indexToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isLong", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reserveAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "realisedPnl", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "markPrice", + "type": "uint256" + } + ], + "name": "LiquidatePosition", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "usdgAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeBasisPoints", + "type": "uint256" + } + ], + "name": "SellUSDG", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOutAfterFees", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeBasisPoints", + "type": "uint256" + } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fundingRate", + "type": "uint256" + } + ], + "name": "UpdateFundingRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bool", + "name": "hasProfit", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delta", + "type": "uint256" + } + ], + "name": "UpdatePnl", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "key", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "averagePrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "entryFundingRate", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reserveAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "realisedPnl", + "type": "int256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "markPrice", + "type": "uint256" + } + ], + "name": "UpdatePosition", + "type": "event" + }, + { + "inputs": [], + "name": "BASIS_POINTS_DIVISOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "FUNDING_RATE_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_FEE_BASIS_POINTS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_FUNDING_RATE_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_LIQUIDATION_FEE_USD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_FUNDING_RATE_INTERVAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_LEVERAGE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PRICE_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "USDG_DECIMALS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_router", + "type": "address" + } + ], + "name": "addRouter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_tokenDiv", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenMul", + "type": "address" + } + ], + "name": "adjustForDecimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "allWhitelistedTokens", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "allWhitelistedTokensLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "approvedRouters", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "blockInfo", + "outputs": [ + { + "internalType": "contract IBlockInfo", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "bufferAmounts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_receiver", + "type": "address" + } + ], + "name": "buyUSDG", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "clearTokenConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "cumulativeFundingRates", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collateralDelta", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_sizeDelta", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + }, + { + "internalType": "address", + "name": "_receiver", + "type": "address" + } + ], + "name": "decreasePosition", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "delegatePartOne", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "delegatePartThree", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "delegatePartTwo", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "directPoolDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "errorController", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "errors", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "feeReserves", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fundingInterval", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fundingRateFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_averagePrice", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_lastIncreasedTime", + "type": "uint256" + } + ], + "name": "getDelta", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + } + ], + "name": "getEntryFundingRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_usdgDelta", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_feeBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_taxBasisPoints", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_increment", + "type": "bool" + } + ], + "name": "getFeeBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_entryFundingRate", + "type": "uint256" + } + ], + "name": "getFundingFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getGlobalShortDelta", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getMaxPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getMinPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_averagePrice", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_nextPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_sizeDelta", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_lastIncreasedTime", + "type": "uint256" + } + ], + "name": "getNextAveragePrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getNextFundingRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_nextPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_sizeDelta", + "type": "uint256" + } + ], + "name": "getNextGlobalShortAveragePrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + } + ], + "name": "getPosition", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + } + ], + "name": "getPositionDelta", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_sizeDelta", + "type": "uint256" + } + ], + "name": "getPositionFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + } + ], + "name": "getPositionKey", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + } + ], + "name": "getPositionLeverage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_usdgAmount", + "type": "uint256" + } + ], + "name": "getRedemptionAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getRedemptionCollateral", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getRedemptionCollateralUsd", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getTargetUsdgAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getUtilisation", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "globalShortAveragePrices", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "globalShortSizes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gov", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "guaranteedUsd", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hasDynamicFees", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "inManagerMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "inPrivateLiquidationMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "includeAmmPrice", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_sizeDelta", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + } + ], + "name": "increasePosition", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_router", + "type": "address" + }, + { + "internalType": "address", + "name": "_usdg", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeed", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_liquidationFeeUsd", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_fundingRateFactor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_stableFundingRateFactor", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isLeverageEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isLiquidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isManager", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isSwapEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "lastFundingTimes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + }, + { + "internalType": "address", + "name": "_feeReceiver", + "type": "address" + } + ], + "name": "liquidatePosition", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquidationFeeUsd", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "marginFeeBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxGasPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxGlobalShortSizes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLeverage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxUsdgAmounts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "minProfitBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minProfitTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mintBurnFeeBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "poolAmounts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "positions", + "outputs": [ + { + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "averagePrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "entryFundingRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserveAmount", + "type": "uint256" + }, + { + "internalType": "int256", + "name": "realisedPnl", + "type": "int256" + }, + { + "internalType": "uint256", + "name": "lastIncreasedTime", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_router", + "type": "address" + } + ], + "name": "removeRouter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "reservedAmounts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "router", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_receiver", + "type": "address" + } + ], + "name": "sellUSDG", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "setBufferAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_errorCode", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_error", + "type": "string" + } + ], + "name": "setError", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_errorController", + "type": "address" + } + ], + "name": "setErrorController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_taxBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_stableTaxBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_mintBurnFeeBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_swapFeeBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_stableSwapFeeBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_marginFeeBasisPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_liquidationFeeUsd", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minProfitTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_hasDynamicFees", + "type": "bool" + } + ], + "name": "setFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_fundingInterval", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_fundingRateFactor", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_stableFundingRateFactor", + "type": "uint256" + } + ], + "name": "setFundingRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gov", + "type": "address" + } + ], + "name": "setGov", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_inManagerMode", + "type": "bool" + } + ], + "name": "setInManagerMode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_inPrivateLiquidationMode", + "type": "bool" + } + ], + "name": "setInPrivateLiquidationMode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_isLeverageEnabled", + "type": "bool" + } + ], + "name": "setIsLeverageEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_isSwapEnabled", + "type": "bool" + } + ], + "name": "setIsSwapEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_liquidator", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isActive", + "type": "bool" + } + ], + "name": "setLiquidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_manager", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isManager", + "type": "bool" + } + ], + "name": "setManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxGasPrice", + "type": "uint256" + } + ], + "name": "setMaxGasPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "setMaxGlobalShortSize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxLeverage", + "type": "uint256" + } + ], + "name": "setMaxLeverage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_priceFeed", + "type": "address" + } + ], + "name": "setPriceFeed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_router", + "type": "address" + } + ], + "name": "setRouter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenDecimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenWeight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minProfitBps", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxUsdgAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isStable", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_isShortable", + "type": "bool" + } + ], + "name": "setTokenConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "setUsdgAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IVaultUtils", + "name": "_vaultUtils", + "type": "address" + } + ], + "name": "setVaultUtils", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "shortableTokens", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stableFundingRateFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stableSwapFeeBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stableTaxBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "stableTokens", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenIn", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenOut", + "type": "address" + }, + { + "internalType": "address", + "name": "_receiver", + "type": "address" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "swapFeeBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "taxBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "tokenBalances", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "tokenDecimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenAmount", + "type": "uint256" + } + ], + "name": "tokenToUsdMin", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "tokenWeights", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalTokenWeights", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + } + ], + "name": "updateCumulativeFundingRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVault", + "type": "address" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "upgradeVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_usdAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "usdToToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_usdAmount", + "type": "uint256" + } + ], + "name": "usdToTokenMax", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_usdAmount", + "type": "uint256" + } + ], + "name": "usdToTokenMin", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "usdg", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "usdgAmounts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "useSwapPricing", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + }, + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_indexToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isLong", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_raise", + "type": "bool" + } + ], + "name": "validateLiquidation", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaultUtils", + "outputs": [ + { + "internalType": "contract IVaultUtils", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "whitelistedTokenCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "whitelistedTokens", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_receiver", + "type": "address" + } + ], + "name": "withdrawFees", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/pkg/source/zkera-finance/abis/VaultPriceFeed.json b/pkg/source/zkera-finance/abis/VaultPriceFeed.json new file mode 100644 index 000000000..3a9e17463 --- /dev/null +++ b/pkg/source/zkera-finance/abis/VaultPriceFeed.json @@ -0,0 +1,888 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "BASIS_POINTS_DIVISOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_ADJUSTMENT_BASIS_POINTS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_ADJUSTMENT_INTERVAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_SPREAD_BASIS_POINTS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ONE_USD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PRICE_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "adjustmentBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bnb", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bnbBusd", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "btc", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "btcBnb", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "chainlinkFlags", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "eth", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ethBnb", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "favorPrimaryPrice", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "getAmmPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_maximise", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_primaryPrice", + "type": "uint256" + } + ], + "name": "getAmmPriceV2", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_pair", + "type": "address" + }, + { + "internalType": "bool", + "name": "_divByReserve0", + "type": "bool" + } + ], + "name": "getPairPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_maximise", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_includeAmmPrice", + "type": "bool" + }, + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "name": "getPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_maximise", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_includeAmmPrice", + "type": "bool" + } + ], + "name": "getPriceV1", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_maximise", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_includeAmmPrice", + "type": "bool" + } + ], + "name": "getPriceV2", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_maximise", + "type": "bool" + } + ], + "name": "getPrimaryPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_referencePrice", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_maximise", + "type": "bool" + } + ], + "name": "getSecondaryPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gov", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isAdjustmentAdditive", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isAmmEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isSecondaryPriceEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "lastAdjustmentTimings", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxStrictPriceDeviation", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "priceDecimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "priceFeeds", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceSampleSpace", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "secondaryPriceFeed", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_isAdditive", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_adjustmentBps", + "type": "uint256" + } + ], + "name": "setAdjustment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_chainlinkFlags", + "type": "address" + } + ], + "name": "setChainlinkFlags", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_favorPrimaryPrice", + "type": "bool" + } + ], + "name": "setFavorPrimaryPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gov", + "type": "address" + } + ], + "name": "setGov", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_isEnabled", + "type": "bool" + } + ], + "name": "setIsAmmEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_isEnabled", + "type": "bool" + } + ], + "name": "setIsSecondaryPriceEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxStrictPriceDeviation", + "type": "uint256" + } + ], + "name": "setMaxStrictPriceDeviation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_bnbBusd", + "type": "address" + }, + { + "internalType": "address", + "name": "_ethBnb", + "type": "address" + }, + { + "internalType": "address", + "name": "_btcBnb", + "type": "address" + } + ], + "name": "setPairs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_priceSampleSpace", + "type": "uint256" + } + ], + "name": "setPriceSampleSpace", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_secondaryPriceFeed", + "type": "address" + } + ], + "name": "setSecondaryPriceFeed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_spreadBasisPoints", + "type": "uint256" + } + ], + "name": "setSpreadBasisPoints", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_spreadThresholdBasisPoints", + "type": "uint256" + } + ], + "name": "setSpreadThresholdBasisPoints", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeed", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_priceDecimals", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isStrictStable", + "type": "bool" + } + ], + "name": "setTokenConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_btc", + "type": "address" + }, + { + "internalType": "address", + "name": "_eth", + "type": "address" + }, + { + "internalType": "address", + "name": "_bnb", + "type": "address" + } + ], + "name": "setTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_useV2Pricing", + "type": "bool" + } + ], + "name": "setUseV2Pricing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "spreadBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "spreadThresholdBasisPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "strictStableTokens", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "useV2Pricing", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/pkg/source/zkera-finance/config.go b/pkg/source/zkera-finance/config.go new file mode 100644 index 000000000..507cc8b44 --- /dev/null +++ b/pkg/source/zkera-finance/config.go @@ -0,0 +1,7 @@ +package zkerafinance + +type Config struct { + DexID string `json:"dexID"` + VaultAddress string `json:"vaultAddress"` + UseSecondaryPriceFeedV1 bool `json:"useSecondaryPriceFeedV1"` +} diff --git a/pkg/source/zkera-finance/constants.go b/pkg/source/zkera-finance/constants.go new file mode 100644 index 000000000..ecc547f5b --- /dev/null +++ b/pkg/source/zkera-finance/constants.go @@ -0,0 +1,13 @@ +package zkerafinance + +import "math/big" + +const DexType = "zkera-finance" + +var ( + DefaultGas = Gas{Swap: 165000} + BasisPointsDivisor = big.NewInt(10000) + PricePrecision = new(big.Int).Exp(big.NewInt(10), big.NewInt(30), nil) + USDGDecimals = big.NewInt(18) + OneUSD = PricePrecision +) diff --git a/pkg/source/zkera-finance/embed.go b/pkg/source/zkera-finance/embed.go new file mode 100644 index 000000000..f2bf292d2 --- /dev/null +++ b/pkg/source/zkera-finance/embed.go @@ -0,0 +1,24 @@ +package zkerafinance + +import _ "embed" + +//go:embed abis/FastPriceFeedV1.json +var fastPriceFeedV1Json []byte + +//go:embed abis/FastPriceFeedV2.json +var fastPriceFeedV2Json []byte + +//go:embed abis/PancakePair.json +var pancakePairJson []byte + +//go:embed abis/PriceFeed.json +var priceFeedJson []byte + +//go:embed abis/Vault.json +var vaultJson []byte + +//go:embed abis/VaultPriceFeed.json +var vaultPriceFeedJson []byte + +//go:embed abis/ERC20.json +var erc20Json []byte diff --git a/pkg/source/zkera-finance/errors.go b/pkg/source/zkera-finance/errors.go new file mode 100644 index 000000000..f2a840196 --- /dev/null +++ b/pkg/source/zkera-finance/errors.go @@ -0,0 +1,18 @@ +package zkerafinance + +import "errors" + +var ( + ErrVaultSwapsNotEnabled = errors.New("vault: swaps not enabled") + ErrVaultMaxUsdgExceeded = errors.New("vault: max USDG exceeded") // code: 51 + ErrVaultPoolAmountExceeded = errors.New("vault: poolAmount exceeded") + ErrVaultReserveExceedsPool = errors.New("vault: reserve exceeds pool") // code: 50 + ErrVaultPoolAmountLessThanBufferAmount = errors.New("vault: poolAmount < buffer") + + ErrVaultPriceFeedInvalidPriceFeed = errors.New("vaultPriceFeed: invalid price feed") + ErrVaultPriceFeedInvalidPrice = errors.New("vaultPriceFeed: invalid price") + ErrVaultPriceFeedCouldNotFetchPrice = errors.New("vaultPriceFeed: could not fetch price") + ErrVaultPriceFeedChainlinkFeedsNotUpdated = errors.New("chainlink feeds are not being updated") + + ErrInvalidSecondaryPriceFeedVersion = errors.New("invalid secondary price feed version") +) diff --git a/pkg/source/zkera-finance/fast_price_feed_v1.go b/pkg/source/zkera-finance/fast_price_feed_v1.go new file mode 100644 index 000000000..307fc40d3 --- /dev/null +++ b/pkg/source/zkera-finance/fast_price_feed_v1.go @@ -0,0 +1,118 @@ +package zkerafinance + +import ( + "math/big" + "time" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber" +) + +type FastPriceFeedV1 struct { + DisableFastPriceVoteCount *big.Int `json:"disableFastPriceVoteCount"` + IsSpreadEnabled bool `json:"isSpreadEnabled"` + LastUpdatedAt *big.Int `json:"lastUpdatedAt"` + MaxDeviationBasisPoints *big.Int `json:"maxDeviationBasisPoints"` + MinAuthorizations *big.Int `json:"minAuthorizations"` + PriceDuration *big.Int `json:"priceDuration"` + VolBasisPoints *big.Int `json:"volBasisPoints"` + Prices map[string]*big.Int `json:"prices"` +} + +func (fp FastPriceFeedV1) GetVersion() int { + return int(secondaryPriceFeedVersion1) +} + +func NewFastPriceFeedV1() *FastPriceFeedV1 { + return &FastPriceFeedV1{ + Prices: make(map[string]*big.Int), + } +} + +const ( + fastPriceFeedMethodV1DisableFastPriceVoteCount = "disableFastPriceVoteCount" + fastPriceFeedMethodV1IsSpreadEnabled = "isSpreadEnabled" + fastPriceFeedMethodV1LastUpdatedAt = "lastUpdatedAt" + fastPriceFeedMethodV1MaxDeviationBasisPoints = "maxDeviationBasisPoints" + fastPriceFeedMethodV1MinAuthorizations = "minAuthorizations" + fastPriceFeedMethodV1PriceDuration = "priceDuration" + fastPriceFeedMethodV1Prices = "prices" + fastPriceFeedMethodV1VolBasisPoints = "volBasisPoints" +) + +func (pf *FastPriceFeedV1) GetPrice(token string, refPrice *big.Int, maximise bool) *big.Int { + if new(big.Int).SetInt64(time.Now().Unix()).Cmp(new(big.Int).Add(pf.LastUpdatedAt, pf.PriceDuration)) > 0 { + return refPrice + } + + fastPrice := pf.Prices[token] + if fastPrice.Cmp(bignumber.ZeroBI) == 0 { + return refPrice + } + + maxPrice := new(big.Int).Div(new(big.Int).Mul(refPrice, new(big.Int).Add(BasisPointsDivisor, pf.MaxDeviationBasisPoints)), BasisPointsDivisor) + minPrice := new(big.Int).Div(new(big.Int).Mul(refPrice, new(big.Int).Sub(BasisPointsDivisor, pf.MaxDeviationBasisPoints)), BasisPointsDivisor) + + if pf.favorFastPrice() { + if fastPrice.Cmp(minPrice) >= 0 && fastPrice.Cmp(maxPrice) <= 0 { + if maximise { + if refPrice.Cmp(fastPrice) > 0 { + volPrice := new(big.Int).Div(new(big.Int).Mul(fastPrice, new(big.Int).Add(BasisPointsDivisor, pf.VolBasisPoints)), BasisPointsDivisor) + + if volPrice.Cmp(refPrice) > 0 { + return refPrice + } else { + return volPrice + } + } + + return fastPrice + } + + if refPrice.Cmp(fastPrice) < 0 { + volPrice := new(big.Int).Div(new(big.Int).Mul(fastPrice, new(big.Int).Sub(BasisPointsDivisor, pf.VolBasisPoints)), BasisPointsDivisor) + + if volPrice.Cmp(refPrice) < 0 { + return refPrice + } else { + return volPrice + } + } + + return fastPrice + } + } + + if maximise { + if refPrice.Cmp(fastPrice) > 0 { + return refPrice + } + + if fastPrice.Cmp(maxPrice) > 0 { + return maxPrice + } else { + return fastPrice + } + } + + if refPrice.Cmp(fastPrice) < 0 { + return refPrice + } + + if fastPrice.Cmp(minPrice) < 0 { + return minPrice + } else { + return fastPrice + } +} + +func (pf *FastPriceFeedV1) favorFastPrice() bool { + if pf.IsSpreadEnabled { + return false + } + + if pf.DisableFastPriceVoteCount.Cmp(pf.MinAuthorizations) >= 0 { + return false + } + + return true +} diff --git a/pkg/source/zkera-finance/fast_price_feed_v1_reader.go b/pkg/source/zkera-finance/fast_price_feed_v1_reader.go new file mode 100644 index 000000000..c7b4a3338 --- /dev/null +++ b/pkg/source/zkera-finance/fast_price_feed_v1_reader.go @@ -0,0 +1,107 @@ +package zkerafinance + +import ( + "context" + "math/big" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +type FastPriceFeedV1Reader struct { + abi abi.ABI + ethrpcClient *ethrpc.Client + log logger.Logger +} + +func NewFastPriceFeedV1Reader(ethrpcClient *ethrpc.Client) *FastPriceFeedV1Reader { + return &FastPriceFeedV1Reader{ + abi: fastPriceFeedV1ABI, + ethrpcClient: ethrpcClient, + log: logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "reader": "FastPriceFeedV1Reader", + }), + } +} + +func (r *FastPriceFeedV1Reader) Read( + ctx context.Context, + address string, + tokens []string, +) (*FastPriceFeedV1, error) { + fastPriceFeedV1 := NewFastPriceFeedV1() + + if err := r.readData(ctx, address, fastPriceFeedV1); err != nil { + r.log.Errorf("error when read data: %s", err) + return nil, err + } + + if err := r.readTokenData(ctx, address, fastPriceFeedV1, tokens); err != nil { + r.log.Errorf("error when read token data: %s", err) + return nil, err + } + + return fastPriceFeedV1, nil +} + +// readData +// - DisableFastPriceVoteCount +// - IsSpreadEnabled +// - LastUpdatedAt +// - MaxDeviationBasisPoints +// - MinAuthorizations +// - PriceDuration +// - VolBasisPoints +func (r *FastPriceFeedV1Reader) readData(ctx context.Context, address string, fastPriceFeed *FastPriceFeedV1) error { + callParamsFactory := CallParamsFactory(r.abi, address) + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV1DisableFastPriceVoteCount, nil), []interface{}{&fastPriceFeed.DisableFastPriceVoteCount}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV1IsSpreadEnabled, nil), []interface{}{&fastPriceFeed.IsSpreadEnabled}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV1LastUpdatedAt, nil), []interface{}{&fastPriceFeed.LastUpdatedAt}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV1MaxDeviationBasisPoints, nil), []interface{}{&fastPriceFeed.MaxDeviationBasisPoints}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV1MinAuthorizations, nil), []interface{}{&fastPriceFeed.MinAuthorizations}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV1PriceDuration, nil), []interface{}{&fastPriceFeed.PriceDuration}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV1VolBasisPoints, nil), []interface{}{&fastPriceFeed.VolBasisPoints}) + + _, err := rpcRequest.TryAggregate() + if err != nil { + r.log.Errorf("error when call aggreate request: %s", err) + } + return err +} + +func (r *FastPriceFeedV1Reader) readTokenData( + ctx context.Context, + address string, + fastPriceFeed *FastPriceFeedV1, + tokens []string, +) error { + tokensLen := len(tokens) + + prices := make([]*big.Int, tokensLen) + + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + for i, token := range tokens { + rpcRequest.AddCall(ðrpc.Call{ + ABI: r.abi, + Target: address, + Method: fastPriceFeedMethodV1Prices, + Params: []interface{}{common.HexToAddress(token)}, + }, []interface{}{&prices[i]}) + } + + if _, err := rpcRequest.TryAggregate(); err != nil { + return err + } + + for i, token := range tokens { + fastPriceFeed.Prices[token] = prices[i] + } + + return nil +} diff --git a/pkg/source/zkera-finance/fast_price_feed_v2.go b/pkg/source/zkera-finance/fast_price_feed_v2.go new file mode 100644 index 000000000..b42f8465c --- /dev/null +++ b/pkg/source/zkera-finance/fast_price_feed_v2.go @@ -0,0 +1,137 @@ +package zkerafinance + +import ( + "math/big" + "time" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber" +) + +type FastPriceFeedV2 struct { + DisableFastPriceVoteCount *big.Int `json:"disableFastPriceVoteCount"` + IsSpreadEnabled bool `json:"isSpreadEnabled"` + LastUpdatedAt *big.Int `json:"lastUpdatedAt"` + MaxDeviationBasisPoints *big.Int `json:"maxDeviationBasisPoints"` + MinAuthorizations *big.Int `json:"minAuthorizations"` + PriceDuration *big.Int `json:"priceDuration"` + MaxPriceUpdateDelay *big.Int `json:"maxPriceUpdateDelay"` + SpreadBasisPointsIfChainError *big.Int `json:"spreadBasisPointsIfChainError"` + SpreadBasisPointsIfInactive *big.Int `json:"spreadBasisPointsIfInactive"` + Prices map[string]*big.Int `json:"prices"` + PriceData map[string]PriceDataItem `json:"priceData"` + MaxCumulativeDeltaDiffs map[string]*big.Int `json:"maxCumulativeDeltaDiffs"` +} + +type PriceDataItem struct { + RefPrice *big.Int `json:"refPrice"` + RefTime uint64 `json:"refTime"` + CumulativeRefDelta uint64 `json:"cumulativeRefDelta"` + CumulativeFastDelta uint64 `json:"cumulativeFastDelta"` +} + +func (fp FastPriceFeedV2) GetVersion() int { + return int(secondaryPriceFeedVersion2) +} + +func NewFastPriceFeedV2() *FastPriceFeedV2 { + return &FastPriceFeedV2{ + Prices: make(map[string]*big.Int), + PriceData: make(map[string]PriceDataItem), + MaxCumulativeDeltaDiffs: make(map[string]*big.Int), + } +} + +const ( + fastPriceFeedMethodV2DisableFastPriceVoteCount = "disableFastPriceVoteCount" + fastPriceFeedMethodV2IsSpreadEnabled = "isSpreadEnabled" + fastPriceFeedMethodV2LastUpdatedAt = "lastUpdatedAt" + fastPriceFeedMethodV2MaxDeviationBasisPoints = "maxDeviationBasisPoints" + fastPriceFeedMethodV2MinAuthorizations = "minAuthorizations" + fastPriceFeedMethodV2PriceDuration = "priceDuration" + fastPriceFeedMethodV2MaxPriceUpdateDelay = "maxPriceUpdateDelay" + fastPriceFeedMethodV2SpreadBasisPointsIfChainError = "spreadBasisPointsIfChainError" + fastPriceFeedMethodV2SpreadBasisPointsIfInactive = "spreadBasisPointsIfInactive" + fastPriceFeedMethodV2Prices = "prices" + fastPriceFeedMethodV2MaxCumulativeDeltaDiffs = "maxCumulativeDeltaDiffs" + fastPriceFeedMethodV2GetPriceData = "getPriceData" +) + +func (pf *FastPriceFeedV2) GetPrice(token string, refPrice *big.Int, maximise bool) *big.Int { + if new(big.Int).SetInt64(time.Now().Unix()).Cmp(new(big.Int).Add(pf.LastUpdatedAt, pf.MaxPriceUpdateDelay)) > 0 { + if maximise { + return new(big.Int).Div(new(big.Int).Mul(refPrice, new(big.Int).Add(BasisPointsDivisor, pf.SpreadBasisPointsIfChainError)), BasisPointsDivisor) + } + + return new(big.Int).Div(new(big.Int).Mul(refPrice, new(big.Int).Sub(BasisPointsDivisor, pf.SpreadBasisPointsIfChainError)), BasisPointsDivisor) + } + + if new(big.Int).SetInt64(time.Now().Unix()).Cmp(new(big.Int).Add(pf.LastUpdatedAt, pf.PriceDuration)) > 0 { + if maximise { + return new(big.Int).Div(new(big.Int).Mul(refPrice, new(big.Int).Add(BasisPointsDivisor, pf.SpreadBasisPointsIfInactive)), BasisPointsDivisor) + } + + return new(big.Int).Div(new(big.Int).Mul(refPrice, new(big.Int).Sub(BasisPointsDivisor, pf.SpreadBasisPointsIfInactive)), BasisPointsDivisor) + } + + fastPrice := pf.Prices[token] + if fastPrice.Cmp(bignumber.ZeroBI) == 0 { + return refPrice + } + + var diffBasisPoints *big.Int + if refPrice.Cmp(fastPrice) > 0 { + diffBasisPoints = new(big.Int).Sub(refPrice, fastPrice) + } else { + diffBasisPoints = new(big.Int).Sub(fastPrice, refPrice) + } + + diffBasisPoints = new(big.Int).Div(new(big.Int).Mul(diffBasisPoints, BasisPointsDivisor), refPrice) + + hasSpread := !pf.favorFastPrice(token) || diffBasisPoints.Cmp(pf.MaxDeviationBasisPoints) > 0 + + if hasSpread { + if maximise { + if refPrice.Cmp(fastPrice) > 0 { + return refPrice + } + + return fastPrice + } + + if refPrice.Cmp(fastPrice) < 0 { + return refPrice + } + + return fastPrice + } + + return fastPrice +} + +func (pf *FastPriceFeedV2) favorFastPrice(token string) bool { + if pf.IsSpreadEnabled { + return false + } + + if pf.DisableFastPriceVoteCount.Cmp(pf.MinAuthorizations) >= 0 { + return false + } + + _, _, cumulativeRefDelta, cumulativeFastDelta := pf.getPriceData(token) + + if cumulativeFastDelta.Cmp(cumulativeRefDelta) > 0 && + new(big.Int).Sub(cumulativeFastDelta, cumulativeRefDelta).Cmp(pf.MaxCumulativeDeltaDiffs[token]) > 0 { + return false + } + + return true +} + +func (pf *FastPriceFeedV2) getPriceData(token string) (*big.Int, *big.Int, *big.Int, *big.Int) { + priceDataItem := pf.PriceData[token] + + return priceDataItem.RefPrice, + new(big.Int).SetUint64(priceDataItem.RefTime), + new(big.Int).SetUint64(priceDataItem.CumulativeRefDelta), + new(big.Int).SetUint64(priceDataItem.CumulativeFastDelta) +} diff --git a/pkg/source/zkera-finance/fast_price_feed_v2_reader.go b/pkg/source/zkera-finance/fast_price_feed_v2_reader.go new file mode 100644 index 000000000..0f6b63483 --- /dev/null +++ b/pkg/source/zkera-finance/fast_price_feed_v2_reader.go @@ -0,0 +1,112 @@ +package zkerafinance + +import ( + "context" + "math/big" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +type FastPriceFeedV2Reader struct { + abi abi.ABI + ethrpcClient *ethrpc.Client + log logger.Logger +} + +func NewFastPriceFeedV2Reader(ethrpcClient *ethrpc.Client) *FastPriceFeedV2Reader { + return &FastPriceFeedV2Reader{ + abi: fastPriceFeedV2ABI, + ethrpcClient: ethrpcClient, + log: logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "reader": "FastPriceFeedV2Reader", + }), + } +} + +func (r *FastPriceFeedV2Reader) Read( + ctx context.Context, + address string, + tokens []string, +) (*FastPriceFeedV2, error) { + fastPriceFeedV2 := NewFastPriceFeedV2() + + if err := r.readData(ctx, address, fastPriceFeedV2); err != nil { + r.log.Errorf("error when read data: %s", err) + return nil, err + } + + if err := r.readTokenData(ctx, address, fastPriceFeedV2, tokens); err != nil { + r.log.Errorf("error when read token data: %s", err) + return nil, err + } + + return fastPriceFeedV2, nil +} + +// readData +// - DisableFastPriceVoteCount +// - IsSpreadEnabled +// - LastUpdatedAt +// - MaxDeviationBasisPoints +// - MinAuthorizations +// - PriceDuration +// - MaxPriceUpdateDelay +// - SpreadBasisPointsIfChainError +// - SpreadBasisPointsIfInactive +func (r *FastPriceFeedV2Reader) readData(ctx context.Context, address string, fastPriceFeed *FastPriceFeedV2) error { + + callParamsFactory := CallParamsFactory(r.abi, address) + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2DisableFastPriceVoteCount, nil), []interface{}{&fastPriceFeed.DisableFastPriceVoteCount}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2IsSpreadEnabled, nil), []interface{}{&fastPriceFeed.IsSpreadEnabled}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2LastUpdatedAt, nil), []interface{}{&fastPriceFeed.LastUpdatedAt}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2MaxDeviationBasisPoints, nil), []interface{}{&fastPriceFeed.MaxDeviationBasisPoints}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2MinAuthorizations, nil), []interface{}{&fastPriceFeed.MinAuthorizations}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2PriceDuration, nil), []interface{}{&fastPriceFeed.PriceDuration}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2MaxPriceUpdateDelay, nil), []interface{}{&fastPriceFeed.MaxPriceUpdateDelay}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2SpreadBasisPointsIfChainError, nil), []interface{}{&fastPriceFeed.SpreadBasisPointsIfChainError}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2SpreadBasisPointsIfInactive, nil), []interface{}{&fastPriceFeed.SpreadBasisPointsIfInactive}) + + _, err := rpcRequest.TryAggregate() + return err + +} + +func (r *FastPriceFeedV2Reader) readTokenData( + ctx context.Context, + address string, + fastPriceFeed *FastPriceFeedV2, + tokens []string, +) error { + tokensLen := len(tokens) + + prices := make([]*big.Int, tokensLen) + maxCumulativeDeltaDiffs := make([]*big.Int, tokensLen) + priceData := make([]PriceDataItem, tokensLen) + callParamsFactory := CallParamsFactory(r.abi, address) + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + for i, token := range tokens { + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2Prices, []interface{}{common.HexToAddress(token)}), []interface{}{&prices[i]}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2MaxCumulativeDeltaDiffs, []interface{}{common.HexToAddress(token)}), []interface{}{&maxCumulativeDeltaDiffs[i]}) + rpcRequest.AddCall(callParamsFactory(fastPriceFeedMethodV2GetPriceData, []interface{}{common.HexToAddress(token)}), []interface{}{&priceData[i]}) + } + + if _, err := rpcRequest.TryAggregate(); err != nil { + r.log.Errorf("error when call aggreate request: %s", err) + return err + } + + for i, token := range tokens { + fastPriceFeed.Prices[token] = prices[i] + fastPriceFeed.MaxCumulativeDeltaDiffs[token] = maxCumulativeDeltaDiffs[i] + fastPriceFeed.PriceData[token] = priceData[i] + } + + return nil +} diff --git a/pkg/source/zkera-finance/helper.go b/pkg/source/zkera-finance/helper.go new file mode 100644 index 000000000..e8b66419a --- /dev/null +++ b/pkg/source/zkera-finance/helper.go @@ -0,0 +1,17 @@ +package zkerafinance + +import ( + "github.com/KyberNetwork/ethrpc" + "github.com/ethereum/go-ethereum/accounts/abi" +) + +func CallParamsFactory(abi abi.ABI, address string) func(callMethod string, params []interface{}) *ethrpc.Call { + return func(callMethod string, params []interface{}) *ethrpc.Call { + return ðrpc.Call{ + ABI: abi, + Target: address, + Method: callMethod, + Params: params, + } + } +} diff --git a/pkg/source/zkera-finance/iface.go b/pkg/source/zkera-finance/iface.go new file mode 100644 index 000000000..8cd6a42b0 --- /dev/null +++ b/pkg/source/zkera-finance/iface.go @@ -0,0 +1,54 @@ +package zkerafinance + +// NOTE: we generate mock files in the same package to avoid cycle dependencies +//go:generate mockgen -destination ./mock_vault_reader.go -package gmx pool-service/internal/dex/gmx IVaultReader +//go:generate mockgen -destination ./mock_vault_price_feed_reader.go -package gmx pool-service/internal/dex/gmx IVaultPriceFeedReader +//go:generate mockgen -destination ./mock_fast_price_feed_reader_v1.go -package gmx pool-service/internal/dex/gmx IFastPriceFeedV1Reader +//go:generate mockgen -destination ./mock_price_feed_reader.go -package gmx pool-service/internal/dex/gmx IPriceFeedReader +//go:generate mockgen -destination ./mock_usdg_reader.go -package gmx pool-service/internal/dex/gmx IUSDGReader +//go:generate mockgen -destination ./mock_chainlink_flags_reader.go -package gmx pool-service/internal/dex/gmx IChainlinkFlagsReader +//go:generate mockgen -destination ./mock_pancake_pair_reader.go -package gmx pool-service/internal/dex/gmx IPancakePairReader + +import ( + "context" + "math/big" +) + +// IVaultReader reads vault smart contract +type IVaultReader interface { + Read(ctx context.Context, address string) (*Vault, error) +} + +// IVaultPriceFeedReader reads vault price feed smart contract +type IVaultPriceFeedReader interface { + Read(ctx context.Context, address string, tokens []string) (*VaultPriceFeed, error) +} + +// IFastPriceFeedV1Reader reads fast price feed smart contract +type IFastPriceFeedV1Reader interface { + Read(ctx context.Context, address string, tokens []string) (*FastPriceFeedV1, error) +} + +type IFastPriceFeedV2Reader interface { + Read(ctx context.Context, address string, tokens []string) (*FastPriceFeedV2, error) +} + +// IPriceFeedReader reads price feed smart contract +type IPriceFeedReader interface { + Read(ctx context.Context, address string) (*PriceFeed, error) +} + +// IUSDGReader reads usdg smart contract +type IUSDGReader interface { + Read(ctx context.Context, address string) (*USDG, error) +} + +// IPancakePairReader reads pancake pair smart contract +type IPancakePairReader interface { + Read(ctx context.Context, address string) (*PancakePair, error) +} + +type IFastPriceFeed interface { + GetVersion() int + GetPrice(token string, refPrice *big.Int, maximise bool) *big.Int +} diff --git a/pkg/source/zkera-finance/pancake_pair.go b/pkg/source/zkera-finance/pancake_pair.go new file mode 100644 index 000000000..77d7d7a42 --- /dev/null +++ b/pkg/source/zkera-finance/pancake_pair.go @@ -0,0 +1,20 @@ +package zkerafinance + +import "math/big" + +type PancakePair struct { + Reserves []*big.Int `json:"reserves"` + TimestampLast uint32 `json:"timestampLast"` +} + +func NewPancakePair() *PancakePair { + return &PancakePair{} +} + +const ( + pancakePairMethodGetReserves = "getReserves" +) + +func (p *PancakePair) GetReserves() (*big.Int, *big.Int, uint32) { + return p.Reserves[0], p.Reserves[1], p.TimestampLast +} diff --git a/pkg/source/zkera-finance/pancake_pair_reader.go b/pkg/source/zkera-finance/pancake_pair_reader.go new file mode 100644 index 000000000..8010e9bf6 --- /dev/null +++ b/pkg/source/zkera-finance/pancake_pair_reader.go @@ -0,0 +1,57 @@ +package zkerafinance + +import ( + "context" + "math/big" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + "github.com/ethereum/go-ethereum/accounts/abi" +) + +type PancakePairReader struct { + abi abi.ABI + ethrpcClient *ethrpc.Client + log logger.Logger +} + +func NewPancakePairReader(ethrpcClient *ethrpc.Client) *PancakePairReader { + return &PancakePairReader{ + abi: pancakePairABI, + ethrpcClient: ethrpcClient, + log: logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "reader": "PancakePairReader", + }), + } +} + +func (r *PancakePairReader) Read(ctx context.Context, address string) (*PancakePair, error) { + var reserves struct { + Reserve0 *big.Int + Reserve1 *big.Int + BlockTimestampLast uint32 + } + + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + rpcRequest.AddCall(ðrpc.Call{ + ABI: r.abi, + Target: address, + Method: pancakePairMethodGetReserves, + Params: nil, + }, []interface{}{&reserves}) + + if _, err := rpcRequest.Call(); err != nil { + r.log.Errorf("error when call rpc request %v", err) + return nil, err + } + + return &PancakePair{ + Reserves: []*big.Int{ + reserves.Reserve0, + reserves.Reserve1, + }, + TimestampLast: reserves.BlockTimestampLast, + }, nil +} diff --git a/pkg/source/zkera-finance/pool_simulator.go b/pkg/source/zkera-finance/pool_simulator.go new file mode 100644 index 000000000..290166ae0 --- /dev/null +++ b/pkg/source/zkera-finance/pool_simulator.go @@ -0,0 +1,223 @@ +package zkerafinance + +import ( + "encoding/json" + "math/big" + "strings" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/entity" + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool" + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber" +) + +type Gas struct { + Swap int64 +} + +type PoolSimulator struct { + pool.Pool + + vault *Vault + vaultUtils *VaultUtils + gas Gas +} + +func NewPoolSimulator(entityPool entity.Pool) (*PoolSimulator, error) { + var extra Extra + if err := json.Unmarshal([]byte(entityPool.Extra), &extra); err != nil { + return nil, err + } + + tokens := make([]string, 0, len(entityPool.Tokens)) + for _, poolToken := range entityPool.Tokens { + tokens = append(tokens, poolToken.Address) + } + + info := pool.PoolInfo{ + Address: entityPool.Address, + Exchange: entityPool.Exchange, + Type: entityPool.Type, + Tokens: tokens, + } + + return &PoolSimulator{ + Pool: pool.Pool{ + Info: info, + }, + vault: extra.Vault, + vaultUtils: NewVaultUtils(extra.Vault), + gas: DefaultGas, + }, nil +} + +func (p *PoolSimulator) CalcAmountOut(param pool.CalcAmountOutParams) (*pool.CalcAmountOutResult, error) { + tokenAmountIn, tokenOut := param.TokenAmountIn, param.TokenOut + + amountOutAfterFees, feeAmount, err := p.getAmountOut(tokenAmountIn.Token, tokenOut, tokenAmountIn.Amount) + if err != nil { + return &pool.CalcAmountOutResult{}, err + } + + tokenAmountOut := &pool.TokenAmount{ + Token: tokenOut, + Amount: amountOutAfterFees, + } + tokenAmountFee := &pool.TokenAmount{ + Token: tokenOut, + Amount: feeAmount, + } + + return &pool.CalcAmountOutResult{ + TokenAmountOut: tokenAmountOut, + Fee: tokenAmountFee, + Gas: p.gas.Swap, + }, nil +} + +// UpdateBalance update UsdgAmount only +// https://github.com/gmx-io/gmx-contracts/blob/787d767e033c411f6d083f2725fb54b7fa956f7e/contracts/core/Vault.sol#L547-L548 +func (p *PoolSimulator) UpdateBalance(params pool.UpdateBalanceParams) { + input, output, fee := params.TokenAmountIn, params.TokenAmountOut, params.Fee + priceIn, err := p.vault.GetMinPrice(input.Token) + if err != nil { + return + } + + usdgAmount := new(big.Int).Div(new(big.Int).Mul(input.Amount, priceIn), PricePrecision) + usdgAmount = p.vault.AdjustForDecimals(usdgAmount, input.Token, p.vault.USDG.Address) + + p.vault.IncreaseUSDGAmount(input.Token, usdgAmount) + p.vault.DecreaseUSDGAmount(output.Token, usdgAmount) + p.vault.IncreasePoolAmount(input.Token, input.Amount) + p.vault.DecreasePoolAmount(output.Token, new(big.Int).Add(output.Amount, fee.Amount)) +} + +func (p *PoolSimulator) CanSwapFrom(address string) []string { return p.CanSwapTo(address) } + +func (p *PoolSimulator) CanSwapTo(address string) []string { + whitelistedTokens := p.vault.WhitelistedTokens + + isTokenExists := false + for _, token := range whitelistedTokens { + if strings.EqualFold(token, address) { + isTokenExists = true + } + } + + if !isTokenExists { + return nil + } + + swappableTokens := make([]string, 0, len(whitelistedTokens)-1) + for _, token := range whitelistedTokens { + tokenAddress := token + + if address == tokenAddress { + continue + } + + swappableTokens = append(swappableTokens, tokenAddress) + } + + return swappableTokens +} + +func (p *PoolSimulator) GetMetaInfo(_ string, _ string) interface{} { return nil } + +// getAmountOut returns amountOutAfterFees, feeAmount and error +func (p *PoolSimulator) getAmountOut(tokenIn string, tokenOut string, amountIn *big.Int) (*big.Int, *big.Int, error) { + if !p.vault.IsSwapEnabled { + return nil, nil, ErrVaultSwapsNotEnabled + } + + priceIn, err := p.vault.GetMinPrice(tokenIn) + if err != nil { + return nil, nil, err + } + + priceOut, err := p.vault.GetMaxPrice(tokenOut) + if err != nil { + return nil, nil, err + } + + amountOut := new(big.Int).Div(new(big.Int).Mul(amountIn, priceIn), priceOut) + amountOut = p.vault.AdjustForDecimals(amountOut, tokenIn, tokenOut) + + usdgAmount := new(big.Int).Div(new(big.Int).Mul(amountIn, priceIn), PricePrecision) + usdgAmount = p.vault.AdjustForDecimals(usdgAmount, tokenIn, p.vault.USDG.Address) + + // in smart contract, this validation is implemented inside _increaseUsdgAmount method + if err = p.validateMaxUsdgExceed(tokenIn, usdgAmount); err != nil { + return nil, nil, err + } + + // in smart contract, this validation is implemented inside _decreasePoolAmount method + if err = p.validateMinPoolAmount(tokenOut, amountOut); err != nil { + return nil, nil, err + } + + // in smart contract, this validation is implemented inside _validateBufferAmount method + if err = p.validateBufferAmount(tokenOut, amountOut); err != nil { + return nil, nil, err + } + + feeBasisPoints := p.vaultUtils.GetSwapFeeBasisPoints(tokenIn, tokenOut, usdgAmount) + amountOutAfterFees := new(big.Int).Div( + new(big.Int).Mul( + amountOut, + new(big.Int).Sub(BasisPointsDivisor, feeBasisPoints), + ), + BasisPointsDivisor, + ) + + feeAmount := new(big.Int).Sub(amountOut, amountOutAfterFees) + + return amountOutAfterFees, feeAmount, nil +} + +func (p *PoolSimulator) validateMaxUsdgExceed(token string, amount *big.Int) error { + currentUsdgAmount := p.vault.USDGAmounts[token] + newUsdgAmount := new(big.Int).Add(currentUsdgAmount, amount) + + maxUsdgAmount := p.vault.MaxUSDGAmounts[token] + + if maxUsdgAmount.Cmp(bignumber.ZeroBI) == 0 { + return nil + } + + if newUsdgAmount.Cmp(maxUsdgAmount) < 0 { + return nil + } + + return ErrVaultMaxUsdgExceeded +} + +func (p *PoolSimulator) validateMinPoolAmount(token string, amount *big.Int) error { + currentPoolAmount := p.vault.PoolAmounts[token] + + if currentPoolAmount.Cmp(amount) < 0 { + return ErrVaultPoolAmountExceeded + } + + newPoolAmount := new(big.Int).Sub(currentPoolAmount, amount) + reservedAmount := p.vault.ReservedAmounts[token] + + if reservedAmount.Cmp(newPoolAmount) > 0 { + return ErrVaultReserveExceedsPool + } + + return nil +} + +func (p *PoolSimulator) validateBufferAmount(token string, amount *big.Int) error { + currentPoolAmount := p.vault.PoolAmounts[token] + newPoolAmount := new(big.Int).Sub(currentPoolAmount, amount) + + bufferAmount := p.vault.BufferAmounts[token] + + if newPoolAmount.Cmp(bufferAmount) < 0 { + return ErrVaultPoolAmountLessThanBufferAmount + } + + return nil +} diff --git a/pkg/source/zkera-finance/pool_tracker.go b/pkg/source/zkera-finance/pool_tracker.go new file mode 100644 index 000000000..dafb5f7fa --- /dev/null +++ b/pkg/source/zkera-finance/pool_tracker.go @@ -0,0 +1,74 @@ +package zkerafinance + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/entity" + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool" +) + +type PoolTracker struct { + config *Config + ethrpcClient *ethrpc.Client +} + +func NewPoolTracker( + cfg *Config, + ethrpcClient *ethrpc.Client, +) (*PoolTracker, error) { + return &PoolTracker{ + config: cfg, + ethrpcClient: ethrpcClient, + }, nil +} + +func (d *PoolTracker) GetNewPoolState( + ctx context.Context, + p entity.Pool, + _ pool.GetNewPoolStateParams, +) (entity.Pool, error) { + log := logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "poolAddress": p.Address, + }) + log.Info("Start getting new state of pool") + + vault, err := NewVaultScanner(d.config, d.ethrpcClient).getVault(ctx, p.Address) + if err != nil { + log.Errorf("get vault failed: %v", err) + return entity.Pool{}, fmt.Errorf("get vault failed, pool: %s, err: %v", p.Address, err) + } + + poolTokens := make([]*entity.PoolToken, 0, len(vault.WhitelistedTokens)) + reserves := make(entity.PoolReserves, 0, len(vault.WhitelistedTokens)) + for _, token := range vault.WhitelistedTokens { + poolTokens = append(poolTokens, &entity.PoolToken{ + Address: token, + Swappable: true, + }) + reserves = append(reserves, vault.PoolAmounts[token].String()) + } + + extra := Extra{Vault: vault} + + extraBytes, err := json.Marshal(extra) + if err != nil { + log.Errorf("marshal extra failed: %v", err) + return entity.Pool{}, err + } + + p.Extra = string(extraBytes) + p.Reserves = reserves + p.Tokens = poolTokens + p.Timestamp = time.Now().Unix() + + log.Info("Finish getting new state") + + return p, nil +} diff --git a/pkg/source/zkera-finance/pools_list_updater.go b/pkg/source/zkera-finance/pools_list_updater.go new file mode 100644 index 000000000..a5f3d3c26 --- /dev/null +++ b/pkg/source/zkera-finance/pools_list_updater.go @@ -0,0 +1,78 @@ +package zkerafinance + +import ( + "context" + "encoding/json" + "time" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/entity" +) + +type PoolsListUpdater struct { + config *Config + ethrpcClient *ethrpc.Client + hasInitialized bool +} + +func NewPoolsListUpdater( + cfg *Config, + ethrpcClient *ethrpc.Client, +) *PoolsListUpdater { + return &PoolsListUpdater{ + config: cfg, + ethrpcClient: ethrpcClient, + hasInitialized: false, + } +} + +func (d *PoolsListUpdater) GetNewPools(ctx context.Context, metadataBytes []byte) ([]entity.Pool, []byte, error) { + log := logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "kind": "getNewPools", + }) + if d.hasInitialized { + log.Infof("initialized. Ignore making new pools") + return nil, nil, nil + } + + vault, err := NewVaultScanner(d.config, d.ethrpcClient).getVault(ctx, d.config.VaultAddress) + if err != nil { + log.Errorf("get vault failed: %v", err) + return nil, nil, err + } + + poolTokens := make([]*entity.PoolToken, 0, len(vault.WhitelistedTokens)) + reserves := make(entity.PoolReserves, 0, len(vault.WhitelistedTokens)) + for _, token := range vault.WhitelistedTokens { + poolTokens = append(poolTokens, &entity.PoolToken{ + Address: token, + Swappable: true, + }) + reserves = append(reserves, vault.PoolAmounts[token].String()) + } + + extra := Extra{Vault: vault} + + extraBytes, err := json.Marshal(extra) + if err != nil { + log.Errorf("error when marshal extra: %v", err) + return nil, nil, err + } + + pool := entity.Pool{ + Address: d.config.VaultAddress, + Exchange: d.config.DexID, + Type: DexType, + Tokens: poolTokens, + Reserves: reserves, + Extra: string(extraBytes), + Timestamp: time.Now().Unix(), + } + + d.hasInitialized = true + + return []entity.Pool{pool}, nil, nil +} diff --git a/pkg/source/zkera-finance/price_feed.go b/pkg/source/zkera-finance/price_feed.go new file mode 100644 index 000000000..16e7bc24d --- /dev/null +++ b/pkg/source/zkera-finance/price_feed.go @@ -0,0 +1,29 @@ +package zkerafinance + +import ( + "math/big" +) + +var ( + maximizeTrue = "true" + maximizeFalse = "false" +) + +type PriceFeed struct { + LatestAnswers map[string]*big.Int `json:"latestAnswers"` +} + +func NewPriceFeed() *PriceFeed { + return &PriceFeed{ + LatestAnswers: make(map[string]*big.Int), + } +} + +const priceFeedMethodLatestAnswer = "latestAnswer" + +func (pf *PriceFeed) LatestAnswer(maximize bool) *big.Int { + if maximize { + return pf.LatestAnswers[maximizeTrue] + } + return pf.LatestAnswers[maximizeFalse] +} diff --git a/pkg/source/zkera-finance/price_feed_reader.go b/pkg/source/zkera-finance/price_feed_reader.go new file mode 100644 index 000000000..a0a5c4ba8 --- /dev/null +++ b/pkg/source/zkera-finance/price_feed_reader.go @@ -0,0 +1,68 @@ +package zkerafinance + +import ( + "context" + "math/big" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + "github.com/ethereum/go-ethereum/accounts/abi" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber" +) + +type PriceFeedReader struct { + abi abi.ABI + ethrpcClient *ethrpc.Client + log logger.Logger +} + +func NewPriceFeedReader(ethrpcClient *ethrpc.Client) *PriceFeedReader { + return &PriceFeedReader{ + abi: priceFeedABI, + ethrpcClient: ethrpcClient, + log: logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "reader": "PriceFeedReader", + }), + } +} + +func (r *PriceFeedReader) Read(ctx context.Context, address string) (*PriceFeed, error) { + priceFeed := NewPriceFeed() + + var v0, v1 *big.Int + + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + rpcRequest.AddCall(ðrpc.Call{ + ABI: r.abi, + Target: address, + Method: priceFeedMethodLatestAnswer, + Params: []interface{}{true}, + }, []interface{}{&v0}) + + rpcRequest.AddCall(ðrpc.Call{ + ABI: r.abi, + Target: address, + Method: priceFeedMethodLatestAnswer, + Params: []interface{}{false}, + }, []interface{}{&v1}) + + if _, err := rpcRequest.TryAggregate(); err != nil { + logger.Errorf("error when call rpcRequest.Aggregate: %s | %s", err.Error(), address) + return nil, err + } + + if v0 == nil { + v0 = bignumber.ZeroBI + } + if v1 == nil { + v1 = bignumber.ZeroBI + } + + priceFeed.LatestAnswers[maximizeTrue] = v0 + priceFeed.LatestAnswers[maximizeFalse] = v1 + + return priceFeed, nil +} diff --git a/pkg/source/zkera-finance/types.go b/pkg/source/zkera-finance/types.go new file mode 100644 index 000000000..a6658821c --- /dev/null +++ b/pkg/source/zkera-finance/types.go @@ -0,0 +1,18 @@ +package zkerafinance + +type VaultAddress struct { + Vault string `json:"vault"` +} + +type Extra struct { + Vault *Vault `json:"vault"` +} + +type ChainID uint + +type SecondaryPriceFeedVersion int + +const ( + secondaryPriceFeedVersion1 SecondaryPriceFeedVersion = 1 + secondaryPriceFeedVersion2 SecondaryPriceFeedVersion = 2 +) diff --git a/pkg/source/zkera-finance/usdg.go b/pkg/source/zkera-finance/usdg.go new file mode 100644 index 000000000..08cb89c84 --- /dev/null +++ b/pkg/source/zkera-finance/usdg.go @@ -0,0 +1,14 @@ +package zkerafinance + +import ( + "math/big" +) + +type USDG struct { + Address string `json:"address"` + TotalSupply *big.Int `json:"totalSupply"` +} + +const ( + usdgMethodTotalSupply = "totalSupply" +) diff --git a/pkg/source/zkera-finance/usdg_reader.go b/pkg/source/zkera-finance/usdg_reader.go new file mode 100644 index 000000000..df2ab675f --- /dev/null +++ b/pkg/source/zkera-finance/usdg_reader.go @@ -0,0 +1,49 @@ +package zkerafinance + +import ( + "context" + "math/big" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + "github.com/ethereum/go-ethereum/accounts/abi" +) + +type USDGReader struct { + abi abi.ABI + ethrpcClient *ethrpc.Client + log logger.Logger +} + +func NewUSDGReader(ethrpcClient *ethrpc.Client) *USDGReader { + return &USDGReader{ + abi: erc20ABI, + ethrpcClient: ethrpcClient, + log: logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "reader": "USDGReader", + }), + } +} + +func (r *USDGReader) Read(ctx context.Context, address string) (*USDG, error) { + var totalSupply *big.Int + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + rpcRequest.AddCall(ðrpc.Call{ + ABI: r.abi, + Target: address, + Method: usdgMethodTotalSupply, + Params: nil, + }, []interface{}{&totalSupply}) + + if _, err := rpcRequest.Call(); err != nil { + r.log.Errorf("error when call rpc request %v", err) + return nil, err + } + + return &USDG{ + Address: address, + TotalSupply: totalSupply, + }, nil +} diff --git a/pkg/source/zkera-finance/vault.go b/pkg/source/zkera-finance/vault.go new file mode 100644 index 000000000..973995f49 --- /dev/null +++ b/pkg/source/zkera-finance/vault.go @@ -0,0 +1,145 @@ +package zkerafinance + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber" +) + +type Vault struct { + HasDynamicFees bool `json:"hasDynamicFees"` + IncludeAmmPrice bool `json:"includeAmmPrice"` + IsSwapEnabled bool `json:"isSwapEnabled"` + StableSwapFeeBasisPoints *big.Int `json:"stableSwapFeeBasisPoints"` + StableTaxBasisPoints *big.Int `json:"stableTaxBasisPoints"` + SwapFeeBasisPoints *big.Int `json:"swapFeeBasisPoints"` + TaxBasisPoints *big.Int `json:"taxBasisPoints"` + TotalTokenWeights *big.Int `json:"totalTokenWeights"` + + WhitelistedTokens []string `json:"whitelistedTokens"` + PoolAmounts map[string]*big.Int `json:"poolAmounts"` + BufferAmounts map[string]*big.Int `json:"bufferAmounts"` + ReservedAmounts map[string]*big.Int `json:"reservedAmounts"` + TokenDecimals map[string]*big.Int `json:"tokenDecimals"` + StableTokens map[string]bool `json:"stableTokens"` + USDGAmounts map[string]*big.Int `json:"usdgAmounts"` + MaxUSDGAmounts map[string]*big.Int `json:"maxUsdgAmounts"` + TokenWeights map[string]*big.Int `json:"tokenWeights"` + + PriceFeedAddress common.Address `json:"-"` + PriceFeed *VaultPriceFeed `json:"priceFeed"` + + USDGAddress common.Address `json:"-"` + USDG *USDG `json:"usdg"` + + WhitelistedTokensCount *big.Int `json:"-"` + + UseSwapPricing bool `json:"useSwapPricing"` // not used, always false for now +} + +func NewVault() *Vault { + return &Vault{ + PoolAmounts: make(map[string]*big.Int), + BufferAmounts: make(map[string]*big.Int), + ReservedAmounts: make(map[string]*big.Int), + TokenDecimals: make(map[string]*big.Int), + StableTokens: make(map[string]bool), + USDGAmounts: make(map[string]*big.Int), + MaxUSDGAmounts: make(map[string]*big.Int), + TokenWeights: make(map[string]*big.Int), + } +} + +const ( + vaultMethodHasDynamicFees = "hasDynamicFees" + vaultMethodIncludeAmmPrice = "includeAmmPrice" + vaultMethodIsSwapEnabled = "isSwapEnabled" + vaultMethodPriceFeed = "priceFeed" + vaultMethodStableSwapFeeBasisPoints = "stableSwapFeeBasisPoints" + vaultMethodStableTaxBasisPoints = "stableTaxBasisPoints" + vaultMethodSwapFeeBasisPoints = "swapFeeBasisPoints" + vaultMethodTaxBasisPoints = "taxBasisPoints" + vaultMethodTotalTokenWeights = "totalTokenWeights" + vaultMethodUSDG = "usdg" + vaultMethodWhitelistedTokenCount = "whitelistedTokenCount" + + vaultMethodAllWhitelistedTokens = "allWhitelistedTokens" + + vaultMethodPoolAmounts = "poolAmounts" + vaultMethodBufferAmounts = "bufferAmounts" + vaultMethodReservedAmounts = "reservedAmounts" + vaultMethodTokenDecimals = "tokenDecimals" + vaultMethodStableTokens = "stableTokens" + vaultMethodUSDGAmounts = "usdgAmounts" + vaultMethodMaxUSDGAmounts = "maxUsdgAmounts" + vaultMethodTokenWeights = "tokenWeights" +) + +func (v *Vault) GetMinPrice(token string) (*big.Int, error) { + return v.PriceFeed.GetPrice(token, false, v.IncludeAmmPrice, v.UseSwapPricing) +} + +func (v *Vault) GetMaxPrice(token string) (*big.Int, error) { + return v.PriceFeed.GetPrice(token, true, v.IncludeAmmPrice, v.UseSwapPricing) +} + +func (v *Vault) GetTargetUSDGAmount(token string) *big.Int { + supply := v.USDG.TotalSupply + + if supply.Cmp(bignumber.ZeroBI) == 0 { + return bignumber.ZeroBI + } + + weight := v.TokenWeights[token] + + return new(big.Int).Div(new(big.Int).Mul(weight, supply), v.TotalTokenWeights) +} + +func (v *Vault) AdjustForDecimals(amount *big.Int, tokenDiv string, tokenMul string) *big.Int { + var decimalsDiv *big.Int + if tokenDiv == v.USDG.Address { + decimalsDiv = USDGDecimals + } else { + decimalsDiv = v.TokenDecimals[tokenDiv] + } + + var decimalsMul *big.Int + if tokenMul == v.USDG.Address { + decimalsMul = USDGDecimals + } else { + decimalsMul = v.TokenDecimals[tokenMul] + } + + return new(big.Int).Div( + new(big.Int).Mul( + amount, + new(big.Int).Exp(big.NewInt(10), decimalsMul, nil), + ), + new(big.Int).Exp(big.NewInt(10), decimalsDiv, nil), + ) +} + +func (v *Vault) IncreaseUSDGAmount(token string, amount *big.Int) { + v.USDGAmounts[token] = new(big.Int).Add(v.USDGAmounts[token], amount) +} + +func (v *Vault) DecreaseUSDGAmount(token string, amount *big.Int) { + currentUSDGAmount := v.USDGAmounts[token] + + if currentUSDGAmount.Cmp(amount) < 0 { + v.USDGAmounts[token] = bignumber.ZeroBI + return + } + + v.USDGAmounts[token] = new(big.Int).Sub(v.USDGAmounts[token], amount) +} + +func (v *Vault) IncreasePoolAmount(token string, amount *big.Int) { + v.PoolAmounts[token] = new(big.Int).Add(v.PoolAmounts[token], amount) +} + +func (v *Vault) DecreasePoolAmount(token string, amount *big.Int) { + v.PoolAmounts[token] = new(big.Int).Sub(v.PoolAmounts[token], amount) +} diff --git a/pkg/source/zkera-finance/vault_price_feed.go b/pkg/source/zkera-finance/vault_price_feed.go new file mode 100644 index 000000000..763ecc704 --- /dev/null +++ b/pkg/source/zkera-finance/vault_price_feed.go @@ -0,0 +1,435 @@ +package zkerafinance + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber" + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/eth" +) + +type VaultPriceFeed struct { + BNB string `json:"bnb"` + BTC string `json:"btc"` + ETH string `json:"eth"` + FavorPrimaryPrice bool `json:"favorPrimaryPrice"` + IsAmmEnabled bool `json:"isAmmEnabled"` + IsSecondaryPriceEnabled bool `json:"isSecondaryPriceEnabled"` + MaxStrictPriceDeviation *big.Int `json:"maxStrictPriceDeviation"` + PriceSampleSpace *big.Int `json:"priceSampleSpace"` + SpreadThresholdBasisPoints *big.Int `json:"spreadThresholdBasisPoints"` + UseV2Pricing bool `json:"useV2Pricing"` + + PriceDecimals map[string]*big.Int `json:"priceDecimals"` + SpreadBasisPoints map[string]*big.Int `json:"spreadBasisPoints"` + AdjustmentBasisPoints map[string]*big.Int `json:"adjustmentBasisPoints"` + StrictStableTokens map[string]bool `json:"strictStableTokens"` + IsAdjustmentAdditive map[string]bool `json:"isAdjustmentAdditive"` + + BNBBUSDAddress common.Address `json:"-"` + BNBBUSD *PancakePair `json:"bnbBusd,omitempty"` + + BTCBNBAddress common.Address `json:"-"` + BTCBNB *PancakePair `json:"btcBnb,omitempty"` + + ETHBNBAddress common.Address `json:"-"` + ETHBNB *PancakePair `json:"ethBnb,omitempty"` + + SecondaryPriceFeedAddress common.Address `json:"secondaryPriceFeedAddress"` + SecondaryPriceFeed IFastPriceFeed `json:"secondaryPriceFeed"` + SecondaryPriceFeedVersion int `json:"secondaryPriceFeedVersion"` + + PriceFeedsAddresses map[string]common.Address `json:"-"` + PriceFeeds map[string]*PriceFeed `json:"priceFeeds"` +} + +func NewVaultPriceFeed() *VaultPriceFeed { + return &VaultPriceFeed{ + PriceDecimals: make(map[string]*big.Int), + SpreadBasisPoints: make(map[string]*big.Int), + AdjustmentBasisPoints: make(map[string]*big.Int), + StrictStableTokens: make(map[string]bool), + IsAdjustmentAdditive: make(map[string]bool), + PriceFeedsAddresses: make(map[string]common.Address), + PriceFeeds: make(map[string]*PriceFeed), + } +} + +const ( + vaultPriceFeedMethodBNB = "bnb" + vaultPriceFeedMethodBNBBUSD = "bnbBusd" + vaultPriceFeedMethodBTC = "btc" + vaultPriceFeedMethodBTCBNB = "btcBnb" + vaultPriceFeedMethodChainlinkFlags = "chainlinkFlags" + vaultPriceFeedMethodETH = "eth" + vaultPriceFeedMethodETHBNB = "ethBnb" + vaultPriceFeedMethodFavorPrimaryPrice = "favorPrimaryPrice" + vaultPriceFeedMethodIsAmmEnabled = "isAmmEnabled" + vaultPriceFeedMethodIsSecondaryPriceEnabled = "isSecondaryPriceEnabled" + vaultPriceFeedMethodMaxStrictPriceDeviation = "maxStrictPriceDeviation" + vaultPriceFeedMethodPriceSampleSpace = "priceSampleSpace" + vaultPriceFeedMethodSecondaryPriceFeed = "secondaryPriceFeed" + vaultPriceFeedMethodSpreadThresholdBasisPoints = "spreadThresholdBasisPoints" + vaultPriceFeedMethodUseV2Pricing = "useV2Pricing" + + vaultPriceFeedMethodPriceFeeds = "priceFeeds" + vaultPriceFeedMethodPriceDecimals = "priceDecimals" + vaultPriceFeedMethodSpreadBasisPoints = "spreadBasisPoints" + vaultPriceFeedMethodAdjustmentBasisPoints = "adjustmentBasisPoints" + vaultPriceFeedMethodStrictStableTokens = "strictStableTokens" + vaultPriceFeedMethodIsAdjustmentAdditive = "isAdjustmentAdditive" +) + +func (pf *VaultPriceFeed) UnmarshalJSON(bytes []byte) error { + var priceFeed struct { + BNB string `json:"bnb"` + BTC string `json:"btc"` + ETH string `json:"eth"` + FavorPrimaryPrice bool `json:"favorPrimaryPrice"` + IsAmmEnabled bool `json:"isAmmEnabled"` + IsSecondaryPriceEnabled bool `json:"isSecondaryPriceEnabled"` + MaxStrictPriceDeviation *big.Int `json:"maxStrictPriceDeviation"` + SpreadThresholdBasisPoints *big.Int `json:"spreadThresholdBasisPoints"` + UseV2Pricing bool `json:"useV2Pricing"` + PriceDecimals map[string]*big.Int `json:"priceDecimals"` + SpreadBasisPoints map[string]*big.Int `json:"spreadBasisPoints"` + AdjustmentBasisPoints map[string]*big.Int `json:"adjustmentBasisPoints"` + StrictStableTokens map[string]bool `json:"strictStableTokens"` + IsAdjustmentAdditive map[string]bool `json:"isAdjustmentAdditive"` + BNBBUSD *PancakePair `json:"bnbBusd,omitempty"` + BTCBNB *PancakePair `json:"btcBnb,omitempty"` + ETHBNB *PancakePair `json:"ethBnb,omitempty"` + SecondaryPriceFeedVersion int `json:"secondaryPriceFeedVersion"` + PriceFeeds map[string]*PriceFeed `json:"priceFeeds"` + } + + if err := json.Unmarshal(bytes, &priceFeed); err != nil { + return err + } + + pf.BNB = priceFeed.BNB + pf.BTC = priceFeed.BTC + pf.ETH = priceFeed.ETH + pf.FavorPrimaryPrice = priceFeed.FavorPrimaryPrice + pf.IsAmmEnabled = priceFeed.IsAmmEnabled + pf.IsSecondaryPriceEnabled = priceFeed.IsSecondaryPriceEnabled + pf.MaxStrictPriceDeviation = priceFeed.MaxStrictPriceDeviation + pf.SpreadThresholdBasisPoints = priceFeed.SpreadThresholdBasisPoints + pf.UseV2Pricing = priceFeed.UseV2Pricing + pf.PriceDecimals = priceFeed.PriceDecimals + pf.SpreadBasisPoints = priceFeed.SpreadBasisPoints + pf.AdjustmentBasisPoints = priceFeed.AdjustmentBasisPoints + pf.StrictStableTokens = priceFeed.StrictStableTokens + pf.IsAdjustmentAdditive = priceFeed.IsAdjustmentAdditive + pf.BNBBUSD = priceFeed.BNBBUSD + pf.BTCBNB = priceFeed.BTCBNB + pf.ETHBNB = priceFeed.ETHBNB + pf.SecondaryPriceFeedVersion = priceFeed.SecondaryPriceFeedVersion + pf.PriceFeeds = priceFeed.PriceFeeds + + if err := pf.UnmarshalJSONSecondaryPriceFeed(bytes); err != nil { + return err + } + + return nil +} + +func (pf *VaultPriceFeed) UnmarshalJSONSecondaryPriceFeed(bytes []byte) error { + if eth.IsZeroAddress(pf.SecondaryPriceFeedAddress) { + return nil + } + + switch pf.SecondaryPriceFeedVersion { + case 1: + var priceFeed struct { + SecondaryPriceFeed *FastPriceFeedV1 `json:"secondaryPriceFeed"` + } + + if err := json.Unmarshal(bytes, &priceFeed); err != nil { + return nil + } + + pf.SecondaryPriceFeed = priceFeed.SecondaryPriceFeed + case 2: + var priceFeed struct { + SecondaryPriceFeed *FastPriceFeedV2 `json:"secondaryPriceFeed"` + } + + if err := json.Unmarshal(bytes, &priceFeed); err != nil { + return nil + } + + pf.SecondaryPriceFeed = priceFeed.SecondaryPriceFeed + default: + return ErrInvalidSecondaryPriceFeedVersion + } + + return nil +} + +func (pf *VaultPriceFeed) GetPrice(token string, maximise bool, includeAmmPrice bool, _ bool) (*big.Int, error) { + var price *big.Int + var err error + + if pf.UseV2Pricing { + price, err = pf.getPriceV2(token, maximise, includeAmmPrice) + if err != nil { + return nil, err + } + } else { + price, err = pf.getPriceV1(token, maximise, includeAmmPrice) + if err != nil { + return nil, err + } + } + + adjustmentBps := pf.AdjustmentBasisPoints[token] + + if adjustmentBps.Cmp(bignumber.ZeroBI) > 0 { + isAdditive := pf.IsAdjustmentAdditive[token] + + if isAdditive { + price = new(big.Int).Div( + new(big.Int).Mul( + price, + new(big.Int).Add(BasisPointsDivisor, adjustmentBps), + ), + BasisPointsDivisor, + ) + } else { + price = new(big.Int).Div( + new(big.Int).Mul( + price, + new(big.Int).Sub(BasisPointsDivisor, adjustmentBps), + ), + BasisPointsDivisor, + ) + } + } + + return price, nil +} + +func (pf *VaultPriceFeed) getPriceV1(token string, maximise bool, includeAmmPrice bool) (*big.Int, error) { + price, err := pf.getPrimaryPrice(token, maximise) + if err != nil { + return nil, err + } + + if includeAmmPrice && pf.IsAmmEnabled { + ammPrice := pf.getAmmPrice(token) + if ammPrice.Cmp(bignumber.ZeroBI) > 0 { + if maximise && ammPrice.Cmp(price) > 0 { + price = ammPrice + } + if !maximise && ammPrice.Cmp(price) < 0 { + price = ammPrice + } + } + } + + if pf.IsSecondaryPriceEnabled { + price = pf.getSecondaryPrice(token, price, maximise) + } + + if pf.StrictStableTokens[token] { + var delta *big.Int + if price.Cmp(OneUSD) > 0 { + delta = new(big.Int).Sub(price, OneUSD) + } else { + delta = new(big.Int).Sub(OneUSD, price) + } + + if delta.Cmp(pf.MaxStrictPriceDeviation) <= 0 { + return OneUSD, nil + } + + if maximise && price.Cmp(OneUSD) > 0 { + return price, nil + } + + if !maximise && price.Cmp(OneUSD) < 0 { + return price, nil + } + + return OneUSD, nil + } + + spreadBasisPoint := pf.SpreadBasisPoints[token] + + if maximise { + return new(big.Int).Div( + new(big.Int).Mul( + price, + new(big.Int).Add(BasisPointsDivisor, spreadBasisPoint), + ), + BasisPointsDivisor, + ), nil + } + + return new(big.Int).Div( + new(big.Int).Mul( + price, + new(big.Int).Sub(BasisPointsDivisor, spreadBasisPoint), + ), + BasisPointsDivisor, + ), nil +} + +func (pf *VaultPriceFeed) getPriceV2(token string, maximise bool, includeAmmPrice bool) (*big.Int, error) { + price, err := pf.getPrimaryPrice(token, maximise) + if err != nil { + return nil, err + } + + if includeAmmPrice && pf.IsAmmEnabled { + price = pf.getAmmPriceV2(token, maximise, price) + } + + if pf.IsSecondaryPriceEnabled { + price = pf.getSecondaryPrice(token, price, maximise) + } + + if pf.StrictStableTokens[token] { + var delta *big.Int + if price.Cmp(OneUSD) > 0 { + delta = new(big.Int).Sub(price, OneUSD) + } else { + delta = new(big.Int).Sub(OneUSD, price) + } + + if delta.Cmp(pf.MaxStrictPriceDeviation) <= 0 { + return OneUSD, nil + } + + if maximise && price.Cmp(OneUSD) > 0 { + return price, nil + } + + if !maximise && price.Cmp(OneUSD) < 0 { + return price, nil + } + + return OneUSD, nil + } + + spreadBasisPoint := pf.SpreadBasisPoints[token] + + if maximise { + return new(big.Int).Div( + new(big.Int).Mul( + price, + new(big.Int).Add(BasisPointsDivisor, spreadBasisPoint), + ), + BasisPointsDivisor, + ), nil + } + + return new(big.Int).Div( + new(big.Int).Mul( + price, + new(big.Int).Sub(BasisPointsDivisor, spreadBasisPoint), + ), + BasisPointsDivisor, + ), nil +} + +func (pf *VaultPriceFeed) getPrimaryPrice(token string, maximise bool) (*big.Int, error) { + priceFeed, ok := pf.PriceFeeds[token] + if !ok { + return nil, ErrVaultPriceFeedInvalidPriceFeed + } + + price := priceFeed.LatestAnswer(maximise) + if price == nil { + return nil, ErrVaultPriceFeedCouldNotFetchPrice + } + + priceDecimal := pf.PriceDecimals[token] + + return new(big.Int).Div( + new(big.Int).Mul(price, PricePrecision), + new(big.Int).Exp(big.NewInt(10), priceDecimal, nil), + ), nil +} + +func (pf *VaultPriceFeed) getSecondaryPrice(token string, referencePrice *big.Int, maximise bool) *big.Int { + if pf.SecondaryPriceFeed == nil { + return referencePrice + } + + return pf.SecondaryPriceFeed.GetPrice(token, referencePrice, maximise) +} + +func (pf *VaultPriceFeed) getAmmPrice(token string) *big.Int { + if token == pf.BNB { + return pf.getPairPrice(pf.BNBBUSD, true) + } + + if token == pf.ETH { + price0 := pf.getPairPrice(pf.BNBBUSD, true) + price1 := pf.getPairPrice(pf.ETHBNB, true) + + return new(big.Int).Div(new(big.Int).Mul(price0, price1), PricePrecision) + } + + if token == pf.BTC { + price0 := pf.getPairPrice(pf.BNBBUSD, true) + price1 := pf.getPairPrice(pf.BTCBNB, true) + + return new(big.Int).Div(new(big.Int).Mul(price0, price1), PricePrecision) + } + + return bignumber.ZeroBI +} + +func (pf *VaultPriceFeed) getAmmPriceV2(token string, maximise bool, primaryPrice *big.Int) *big.Int { + ammPrice := pf.getAmmPrice(token) + if ammPrice.Cmp(bignumber.ZeroBI) == 0 { + return primaryPrice + } + + var diff *big.Int + if ammPrice.Cmp(primaryPrice) > 0 { + diff = new(big.Int).Sub(ammPrice, primaryPrice) + } else { + diff = new(big.Int).Sub(primaryPrice, ammPrice) + } + + if new(big.Int).Mul(diff, BasisPointsDivisor).Cmp(new(big.Int).Mul(primaryPrice, pf.SpreadThresholdBasisPoints)) < 0 { + if pf.FavorPrimaryPrice { + return primaryPrice + } + return ammPrice + } + + if maximise && ammPrice.Cmp(primaryPrice) > 0 { + return ammPrice + } + + if !maximise && ammPrice.Cmp(primaryPrice) < 0 { + return ammPrice + } + + return primaryPrice +} + +func (pf *VaultPriceFeed) getPairPrice(pair *PancakePair, divByReserve0 bool) *big.Int { + reserve0, reserve1, _ := pair.GetReserves() + + if divByReserve0 { + if reserve0.Cmp(bignumber.ZeroBI) == 0 { + return bignumber.ZeroBI + } + + return new(big.Int).Div(new(big.Int).Mul(reserve1, PricePrecision), reserve0) + } + + if reserve1.Cmp(bignumber.ZeroBI) == 0 { + return bignumber.ZeroBI + } + + return new(big.Int).Div(new(big.Int).Mul(reserve0, PricePrecision), reserve1) +} diff --git a/pkg/source/zkera-finance/vault_price_feed_reader.go b/pkg/source/zkera-finance/vault_price_feed_reader.go new file mode 100644 index 000000000..3a19f4986 --- /dev/null +++ b/pkg/source/zkera-finance/vault_price_feed_reader.go @@ -0,0 +1,131 @@ +package zkerafinance + +import ( + "context" + "math/big" + "strings" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +type VaultPriceFeedReader struct { + abi abi.ABI + ethrpcClient *ethrpc.Client + log logger.Logger +} + +func NewVaultPriceFeedReader(ethrpcClient *ethrpc.Client) *VaultPriceFeedReader { + return &VaultPriceFeedReader{ + abi: vaultPriceFeedABI, + ethrpcClient: ethrpcClient, + log: logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "reader": "VaultPriceFeedReader", + }), + } +} + +func (r *VaultPriceFeedReader) Read( + ctx context.Context, + address string, + tokens []string, +) (*VaultPriceFeed, error) { + vaultPriceFeed := NewVaultPriceFeed() + + if err := r.readData(ctx, address, vaultPriceFeed); err != nil { + r.log.Errorf("error when read data: %s", err) + return nil, err + } + + if err := r.readTokenData(ctx, address, vaultPriceFeed, tokens); err != nil { + r.log.Errorf("error when read token data: %s", err) + return nil, err + } + + return vaultPriceFeed, nil +} + +func (r *VaultPriceFeedReader) readData( + ctx context.Context, + address string, + vaultPriceFeed *VaultPriceFeed, +) error { + var bnb, btc, eth common.Address + + callParamsFactory := CallParamsFactory(r.abi, address) + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodBNB, nil), []interface{}{&bnb}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodBNBBUSD, nil), []interface{}{&vaultPriceFeed.BNBBUSDAddress}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodBTC, nil), []interface{}{&btc}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodBTCBNB, nil), []interface{}{&vaultPriceFeed.BTCBNBAddress}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodETH, nil), []interface{}{ð}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodETHBNB, nil), []interface{}{&vaultPriceFeed.ETHBNBAddress}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodFavorPrimaryPrice, nil), []interface{}{&vaultPriceFeed.FavorPrimaryPrice}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodIsAmmEnabled, nil), []interface{}{&vaultPriceFeed.IsAmmEnabled}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodIsSecondaryPriceEnabled, nil), []interface{}{&vaultPriceFeed.IsSecondaryPriceEnabled}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodMaxStrictPriceDeviation, nil), []interface{}{&vaultPriceFeed.MaxStrictPriceDeviation}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodSecondaryPriceFeed, nil), []interface{}{&vaultPriceFeed.SecondaryPriceFeedAddress}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodSpreadThresholdBasisPoints, nil), []interface{}{&vaultPriceFeed.SpreadThresholdBasisPoints}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodUseV2Pricing, nil), []interface{}{&vaultPriceFeed.UseV2Pricing}) + + if _, err := rpcRequest.TryAggregate(); err != nil { + r.log.Errorf("error when call aggreate request: %s", err) + return err + } + + vaultPriceFeed.BNB = strings.ToLower(bnb.String()) + vaultPriceFeed.BTC = strings.ToLower(btc.String()) + vaultPriceFeed.ETH = strings.ToLower(eth.String()) + + return nil +} + +func (r *VaultPriceFeedReader) readTokenData( + ctx context.Context, + address string, + vaultPriceFeed *VaultPriceFeed, + tokens []string, +) error { + tokensLen := len(tokens) + + priceFeedsAddresses := make([]common.Address, tokensLen) + priceDecimals := make([]*big.Int, tokensLen) + spreadBasisPoints := make([]*big.Int, tokensLen) + adjustmentBasisPoints := make([]*big.Int, tokensLen) + strictStableTokens := make([]bool, tokensLen) + isAdjustmentAdditive := make([]bool, tokensLen) + + callParamsFactory := CallParamsFactory(r.abi, address) + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + for i, token := range tokens { + tokenAddress := common.HexToAddress(token) + + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodPriceFeeds, []interface{}{tokenAddress}), []interface{}{&priceFeedsAddresses[i]}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodPriceDecimals, []interface{}{tokenAddress}), []interface{}{&priceDecimals[i]}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodSpreadBasisPoints, []interface{}{tokenAddress}), []interface{}{&spreadBasisPoints[i]}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodAdjustmentBasisPoints, []interface{}{tokenAddress}), []interface{}{&adjustmentBasisPoints[i]}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodStrictStableTokens, []interface{}{tokenAddress}), []interface{}{&strictStableTokens[i]}) + rpcRequest.AddCall(callParamsFactory(vaultPriceFeedMethodIsAdjustmentAdditive, []interface{}{tokenAddress}), []interface{}{&isAdjustmentAdditive[i]}) + } + + if _, err := rpcRequest.TryAggregate(); err != nil { + r.log.Errorf("error when call aggreate request: %s", err) + return err + } + + for i, token := range tokens { + vaultPriceFeed.PriceFeedsAddresses[token] = priceFeedsAddresses[i] + vaultPriceFeed.PriceDecimals[token] = priceDecimals[i] + vaultPriceFeed.SpreadBasisPoints[token] = spreadBasisPoints[i] + vaultPriceFeed.AdjustmentBasisPoints[token] = adjustmentBasisPoints[i] + vaultPriceFeed.StrictStableTokens[token] = strictStableTokens[i] + vaultPriceFeed.IsAdjustmentAdditive[token] = isAdjustmentAdditive[i] + } + + return nil +} diff --git a/pkg/source/zkera-finance/vault_reader.go b/pkg/source/zkera-finance/vault_reader.go new file mode 100644 index 000000000..698a826b4 --- /dev/null +++ b/pkg/source/zkera-finance/vault_reader.go @@ -0,0 +1,153 @@ +package zkerafinance + +import ( + "context" + "math/big" + "strings" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +type VaultReader struct { + abi abi.ABI + ethrpcClient *ethrpc.Client + log logger.Logger +} + +func NewVaultReader(ethrpcClient *ethrpc.Client) *VaultReader { + return &VaultReader{ + abi: vaultABI, + ethrpcClient: ethrpcClient, + log: logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "reader": "VaultReader", + }), + } +} + +// Read reads all data required for finding route +func (r *VaultReader) Read(ctx context.Context, address string) (*Vault, error) { + vault := NewVault() + + if err := r.readData(ctx, address, vault); err != nil { + r.log.Errorf("error when read data: %s", err) + return nil, err + } + + if err := r.readWhitelistedTokens(ctx, address, vault); err != nil { + r.log.Errorf("error when read white listed token: %s", err) + return nil, err + } + + if err := r.readTokensData(ctx, address, vault); err != nil { + r.log.Errorf("error when read tokens data: %s", err) + return nil, err + } + + return vault, nil +} + +func (r *VaultReader) readData(ctx context.Context, address string, vault *Vault) error { + callParamsFactory := CallParamsFactory(r.abi, address) + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + rpcRequest.AddCall(callParamsFactory(vaultMethodHasDynamicFees, nil), []interface{}{&vault.HasDynamicFees}) + rpcRequest.AddCall(callParamsFactory(vaultMethodIncludeAmmPrice, nil), []interface{}{&vault.IncludeAmmPrice}) + rpcRequest.AddCall(callParamsFactory(vaultMethodIsSwapEnabled, nil), []interface{}{&vault.IsSwapEnabled}) + rpcRequest.AddCall(callParamsFactory(vaultMethodPriceFeed, nil), []interface{}{&vault.PriceFeedAddress}) + rpcRequest.AddCall(callParamsFactory(vaultMethodStableSwapFeeBasisPoints, nil), []interface{}{&vault.StableSwapFeeBasisPoints}) + rpcRequest.AddCall(callParamsFactory(vaultMethodStableTaxBasisPoints, nil), []interface{}{&vault.StableTaxBasisPoints}) + rpcRequest.AddCall(callParamsFactory(vaultMethodSwapFeeBasisPoints, nil), []interface{}{&vault.SwapFeeBasisPoints}) + rpcRequest.AddCall(callParamsFactory(vaultMethodTaxBasisPoints, nil), []interface{}{&vault.TaxBasisPoints}) + rpcRequest.AddCall(callParamsFactory(vaultMethodTotalTokenWeights, nil), []interface{}{&vault.TotalTokenWeights}) + rpcRequest.AddCall(callParamsFactory(vaultMethodUSDG, nil), []interface{}{&vault.USDGAddress}) + rpcRequest.AddCall(callParamsFactory(vaultMethodWhitelistedTokenCount, nil), []interface{}{&vault.WhitelistedTokensCount}) + + _, err := rpcRequest.TryAggregate() + + return err +} + +func (r *VaultReader) readWhitelistedTokens( + ctx context.Context, + address string, + vault *Vault, +) error { + tokensLen := int(vault.WhitelistedTokensCount.Int64()) + + whitelistedTokens := make([]common.Address, tokensLen) + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + + for i := 0; i < tokensLen; i++ { + rpcRequest.AddCall(ðrpc.Call{ + ABI: r.abi, + Target: address, + Method: vaultMethodAllWhitelistedTokens, + Params: []interface{}{new(big.Int).SetInt64(int64(i))}, + }, []interface{}{&whitelistedTokens[i]}) + } + if _, err := rpcRequest.TryAggregate(); err != nil { + return err + } + + tokens := make([]string, tokensLen) + for i := range whitelistedTokens { + tokens[i] = strings.ToLower(whitelistedTokens[i].String()) + } + + vault.WhitelistedTokens = tokens + + return nil +} + +func (r *VaultReader) readTokensData( + ctx context.Context, + address string, + vault *Vault, +) error { + tokensLen := len(vault.WhitelistedTokens) + poolAmounts := make([]*big.Int, tokensLen) + bufferAmounts := make([]*big.Int, tokensLen) + reservedAmounts := make([]*big.Int, tokensLen) + tokenDecimals := make([]*big.Int, tokensLen) + stableTokens := make([]bool, tokensLen) + usdgAmounts := make([]*big.Int, tokensLen) + maxUSDGAmounts := make([]*big.Int, tokensLen) + tokenWeights := make([]*big.Int, tokensLen) + + rpcRequest := r.ethrpcClient.NewRequest().SetContext(ctx) + callParamsFactory := CallParamsFactory(r.abi, address) + + for i, token := range vault.WhitelistedTokens { + tokenAddress := common.HexToAddress(token) + + rpcRequest.AddCall(callParamsFactory(vaultMethodPoolAmounts, []interface{}{tokenAddress}), []interface{}{&poolAmounts[i]}) + rpcRequest.AddCall(callParamsFactory(vaultMethodBufferAmounts, []interface{}{tokenAddress}), []interface{}{&bufferAmounts[i]}) + rpcRequest.AddCall(callParamsFactory(vaultMethodReservedAmounts, []interface{}{tokenAddress}), []interface{}{&reservedAmounts[i]}) + rpcRequest.AddCall(callParamsFactory(vaultMethodTokenDecimals, []interface{}{tokenAddress}), []interface{}{&tokenDecimals[i]}) + rpcRequest.AddCall(callParamsFactory(vaultMethodStableTokens, []interface{}{tokenAddress}), []interface{}{&stableTokens[i]}) + rpcRequest.AddCall(callParamsFactory(vaultMethodUSDGAmounts, []interface{}{tokenAddress}), []interface{}{&usdgAmounts[i]}) + rpcRequest.AddCall(callParamsFactory(vaultMethodMaxUSDGAmounts, []interface{}{tokenAddress}), []interface{}{&maxUSDGAmounts[i]}) + rpcRequest.AddCall(callParamsFactory(vaultMethodTokenWeights, []interface{}{tokenAddress}), []interface{}{&tokenWeights[i]}) + } + + if _, err := rpcRequest.TryAggregate(); err != nil { + return err + } + + for i, token := range vault.WhitelistedTokens { + vault.PoolAmounts[token] = poolAmounts[i] + vault.BufferAmounts[token] = bufferAmounts[i] + vault.ReservedAmounts[token] = reservedAmounts[i] + vault.TokenDecimals[token] = tokenDecimals[i] + vault.StableTokens[token] = stableTokens[i] + vault.USDGAmounts[token] = usdgAmounts[i] + vault.MaxUSDGAmounts[token] = maxUSDGAmounts[i] + vault.TokenWeights[token] = tokenWeights[i] + } + + return nil +} diff --git a/pkg/source/zkera-finance/vault_scanner.go b/pkg/source/zkera-finance/vault_scanner.go new file mode 100644 index 000000000..8cb546bbe --- /dev/null +++ b/pkg/source/zkera-finance/vault_scanner.go @@ -0,0 +1,174 @@ +package zkerafinance + +import ( + "context" + + "github.com/KyberNetwork/ethrpc" + "github.com/KyberNetwork/logger" + "github.com/ethereum/go-ethereum/common" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/eth" +) + +type VaultScanner struct { + config *Config + vaultReader IVaultReader + vaultPriceFeedReader IVaultPriceFeedReader + fastPriceFeedV1Reader IFastPriceFeedV1Reader + fastPriceFeedV2Reader IFastPriceFeedV2Reader + priceFeedReader IPriceFeedReader + usdgReader IUSDGReader + pancakePairReader IPancakePairReader + log logger.Logger +} + +func NewVaultScanner( + config *Config, + ethrpcClient *ethrpc.Client, +) *VaultScanner { + return &VaultScanner{ + config: config, + vaultReader: NewVaultReader(ethrpcClient), + vaultPriceFeedReader: NewVaultPriceFeedReader(ethrpcClient), + fastPriceFeedV1Reader: NewFastPriceFeedV1Reader(ethrpcClient), + fastPriceFeedV2Reader: NewFastPriceFeedV2Reader(ethrpcClient), + priceFeedReader: NewPriceFeedReader(ethrpcClient), + usdgReader: NewUSDGReader(ethrpcClient), + pancakePairReader: NewPancakePairReader(ethrpcClient), + log: logger.WithFields(logger.Fields{ + "liquiditySource": DexType, + "scanner": "VaultScanner", + }), + } +} + +func (vs *VaultScanner) getVault(ctx context.Context, address string) (*Vault, error) { + vault, err := vs.vaultReader.Read(ctx, address) + if err != nil { + vs.log.Errorf("error when vaultReader read: %s", err) + return nil, err + } + + usdg, err := vs.usdgReader.Read(ctx, vault.USDGAddress.String()) + if err != nil { + vs.log.Errorf("error when usdgReader read: %s", err) + return nil, err + } + + vault.USDG = usdg + + vaultPriceFeed, err := vs.getVaultPriceFeed(ctx, vault.PriceFeedAddress.String(), vault.WhitelistedTokens) + if err != nil { + vs.log.Errorf("error when get vaultPriceFeed: %s", err) + return nil, err + } + + vault.PriceFeed = vaultPriceFeed + + return vault, nil +} + +// ================================================================================ + +func (vs *VaultScanner) getVaultPriceFeed(ctx context.Context, address string, tokens []string) (*VaultPriceFeed, error) { + vaultPriceFeed, err := vs.vaultPriceFeedReader.Read(ctx, address, tokens) + if err != nil { + return nil, err + } + + if !eth.IsZeroAddress(vaultPriceFeed.BNBBUSDAddress) { + bnbBusd, err := vs.pancakePairReader.Read(ctx, vaultPriceFeed.BNBBUSDAddress.String()) + if err != nil { + return nil, err + } + + vaultPriceFeed.BNBBUSD = bnbBusd + } + + if !eth.IsZeroAddress(vaultPriceFeed.BTCBNBAddress) { + btcBnb, err := vs.pancakePairReader.Read(ctx, vaultPriceFeed.BTCBNBAddress.String()) + if err != nil { + return nil, err + } + + vaultPriceFeed.BTCBNB = btcBnb + } + + if !eth.IsZeroAddress(vaultPriceFeed.ETHBNBAddress) { + ethBnb, err := vs.pancakePairReader.Read(ctx, vaultPriceFeed.ETHBNBAddress.String()) + if err != nil { + return nil, err + } + + vaultPriceFeed.ETHBNB = ethBnb + } + + if !eth.IsZeroAddress(vaultPriceFeed.SecondaryPriceFeedAddress) { + secondaryPriceFeedVersion := vs.getSecondaryPriceFeedVersion() + vaultPriceFeed.SecondaryPriceFeedVersion = int(secondaryPriceFeedVersion) + + fastPriceFeed, err := vs.getFastPriceFeed( + ctx, + secondaryPriceFeedVersion, + vaultPriceFeed.SecondaryPriceFeedAddress.String(), + tokens, + ) + if err != nil { + return nil, err + } + + vaultPriceFeed.SecondaryPriceFeed = fastPriceFeed + } + + priceFeeds, err := vs.getPriceFeeds(ctx, vaultPriceFeed.PriceFeedsAddresses) + if err != nil { + return nil, err + } + + vaultPriceFeed.PriceFeeds = priceFeeds + + return vaultPriceFeed, nil +} + +func (vs *VaultScanner) getPriceFeeds( + ctx context.Context, + priceFeedAddresses map[string]common.Address, +) (map[string]*PriceFeed, error) { + priceFeeds := make(map[string]*PriceFeed, len(priceFeedAddresses)) + + for tokenAddress, priceFeedAddress := range priceFeedAddresses { + if eth.IsZeroAddress(priceFeedAddress) { + logger.Warnf("priceFeedAddress for token %s is zero address: %s", tokenAddress, priceFeedAddress.Hex()) + continue + } + + priceFeed, err := vs.priceFeedReader.Read(ctx, priceFeedAddress.String()) + if err != nil { + return nil, err + } + + priceFeeds[tokenAddress] = priceFeed + } + + return priceFeeds, nil +} + +func (vs VaultScanner) getFastPriceFeed( + ctx context.Context, + version SecondaryPriceFeedVersion, + address string, + tokens []string, +) (IFastPriceFeed, error) { + if version == secondaryPriceFeedVersion2 { + return vs.fastPriceFeedV2Reader.Read(ctx, address, tokens) + } + + return vs.fastPriceFeedV1Reader.Read(ctx, address, tokens) +} + +func (vs *VaultScanner) getSecondaryPriceFeedVersion() SecondaryPriceFeedVersion { + if vs.config.UseSecondaryPriceFeedV1 { + return secondaryPriceFeedVersion1 + } + return secondaryPriceFeedVersion2 +} diff --git a/pkg/source/zkera-finance/vault_utils.go b/pkg/source/zkera-finance/vault_utils.go new file mode 100644 index 000000000..5f45ba36d --- /dev/null +++ b/pkg/source/zkera-finance/vault_utils.go @@ -0,0 +1,103 @@ +package zkerafinance + +import ( + "math/big" + + constant "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber" +) + +// VaultUtils +// https://github.com/gmx-io/gmx-contracts/blob/master/contracts/core/VaultUtils.sol +type VaultUtils struct { + vault *Vault +} + +func NewVaultUtils(vault *Vault) *VaultUtils { + return &VaultUtils{ + vault: vault, + } +} + +func (u *VaultUtils) GetSwapFeeBasisPoints(tokenIn string, tokenOut string, usdgAmount *big.Int) *big.Int { + isStableSwap := u.vault.StableTokens[tokenIn] && u.vault.StableTokens[tokenOut] + + var baseBps *big.Int + if isStableSwap { + baseBps = u.vault.StableSwapFeeBasisPoints + } else { + baseBps = u.vault.SwapFeeBasisPoints + } + + var taxBps *big.Int + if isStableSwap { + taxBps = u.vault.StableTaxBasisPoints + } else { + taxBps = u.vault.TaxBasisPoints + } + + feeBasisPoints0 := u.GetFeeBasisPoints(tokenIn, usdgAmount, baseBps, taxBps, true) + feeBasisPoints1 := u.GetFeeBasisPoints(tokenOut, usdgAmount, baseBps, taxBps, false) + + if feeBasisPoints0.Cmp(feeBasisPoints1) > 0 { + return feeBasisPoints0 + } else { + return feeBasisPoints1 + } +} + +func (u *VaultUtils) GetFeeBasisPoints(token string, usdgDelta *big.Int, feeBasisPoints *big.Int, taxBasisPoints *big.Int, increment bool) *big.Int { + if !u.vault.HasDynamicFees { + return feeBasisPoints + } + + initialAmount := u.vault.USDGAmounts[token] + nextAmount := new(big.Int).Add(initialAmount, usdgDelta) + + if !increment { + if usdgDelta.Cmp(initialAmount) > 0 { + nextAmount = constant.ZeroBI + } else { + nextAmount = new(big.Int).Sub(initialAmount, usdgDelta) + } + } + + targetAmount := u.vault.GetTargetUSDGAmount(token) + + if targetAmount.Cmp(constant.ZeroBI) == 0 { + return feeBasisPoints + } + + var initialDiff *big.Int + if initialAmount.Cmp(targetAmount) > 0 { + initialDiff = new(big.Int).Sub(initialAmount, targetAmount) + } else { + initialDiff = new(big.Int).Sub(targetAmount, initialAmount) + } + + var nextDiff *big.Int + if nextAmount.Cmp(targetAmount) > 0 { + nextDiff = new(big.Int).Sub(nextAmount, targetAmount) + } else { + nextDiff = new(big.Int).Sub(targetAmount, nextAmount) + } + + if nextDiff.Cmp(initialDiff) < 0 { + rebateBps := new(big.Int).Div(new(big.Int).Mul(taxBasisPoints, initialDiff), targetAmount) + + if rebateBps.Cmp(feeBasisPoints) > 0 { + return constant.ZeroBI + } else { + return new(big.Int).Sub(feeBasisPoints, rebateBps) + } + } + + averageDiff := new(big.Int).Div(new(big.Int).Add(initialDiff, nextDiff), constant.Two) + + if averageDiff.Cmp(targetAmount) > 0 { + averageDiff = targetAmount + } + + taxBps := new(big.Int).Div(new(big.Int).Mul(taxBasisPoints, averageDiff), targetAmount) + + return new(big.Int).Add(feeBasisPoints, taxBps) +} diff --git a/pkg/valueobject/exchange.go b/pkg/valueobject/exchange.go index 4524a2bd7..6076b4af7 100644 --- a/pkg/valueobject/exchange.go +++ b/pkg/valueobject/exchange.go @@ -167,6 +167,7 @@ var ( ExchangeOpx Exchange = "opx" ExchangeFulcrom Exchange = "fulcrom" ExchangeVodoo Exchange = "vodoo" + ExchangeZkEraFinance Exchange = "zkera-finance" ExchangeMakerLidoStETH Exchange = "lido-steth"