diff --git a/CLAUDE.md b/CLAUDE.md index e31e4489e..c8aa6b256 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -96,4 +96,5 @@ RISK_CDN_URL= # Risk score CDN URL (defaults to https://risk.yearn.fi/cdn/ - All addresses must be checksummed for consistency - Price data fetched from multiple sources with fallbacks - Risk scores calculated using 11-factor assessment system -- APY calculations support multiple strategies: Curve, Convex, Velodrome, Aerodrome, etc. \ No newline at end of file +- APY calculations support multiple strategies: Curve, Convex, Velodrome, Aerodrome, etc. +- V3 Vault APRs are sourced from Kong (single source of truth) bypassing direct on-chain Oracle calls. \ No newline at end of file diff --git a/common/contracts/yVaultsV3.APROracle.go b/common/contracts/yVaultsV3.APROracle.go deleted file mode 100644 index 9896a4f61..000000000 --- a/common/contracts/yVaultsV3.APROracle.go +++ /dev/null @@ -1,357 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package contracts - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// YVaultsV3APROracleMetaData contains all meta data concerning the YVaultsV3APROracle contract. -var YVaultsV3APROracleMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vault\",\"type\":\"address\"}],\"name\":\"getCurrentApr\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vault\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"_delta\",\"type\":\"int256\"}],\"name\":\"getExpectedApr\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"apr\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"_debtChange\",\"type\":\"int256\"}],\"name\":\"getStrategyApr\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"oracles\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_oracle\",\"type\":\"address\"}],\"name\":\"setOracle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_strategy\",\"type\":\"address\"}],\"name\":\"weightedApr\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", -} - -// YVaultsV3APROracleABI is the input ABI used to generate the binding from. -// Deprecated: Use YVaultsV3APROracleMetaData.ABI instead. -var YVaultsV3APROracleABI = YVaultsV3APROracleMetaData.ABI - -// YVaultsV3APROracle is an auto generated Go binding around an Ethereum contract. -type YVaultsV3APROracle struct { - YVaultsV3APROracleCaller // Read-only binding to the contract - YVaultsV3APROracleTransactor // Write-only binding to the contract - YVaultsV3APROracleFilterer // Log filterer for contract events -} - -// YVaultsV3APROracleCaller is an auto generated read-only Go binding around an Ethereum contract. -type YVaultsV3APROracleCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// YVaultsV3APROracleTransactor is an auto generated write-only Go binding around an Ethereum contract. -type YVaultsV3APROracleTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// YVaultsV3APROracleFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type YVaultsV3APROracleFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// YVaultsV3APROracleSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type YVaultsV3APROracleSession struct { - Contract *YVaultsV3APROracle // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// YVaultsV3APROracleCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type YVaultsV3APROracleCallerSession struct { - Contract *YVaultsV3APROracleCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// YVaultsV3APROracleTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type YVaultsV3APROracleTransactorSession struct { - Contract *YVaultsV3APROracleTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// YVaultsV3APROracleRaw is an auto generated low-level Go binding around an Ethereum contract. -type YVaultsV3APROracleRaw struct { - Contract *YVaultsV3APROracle // Generic contract binding to access the raw methods on -} - -// YVaultsV3APROracleCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type YVaultsV3APROracleCallerRaw struct { - Contract *YVaultsV3APROracleCaller // Generic read-only contract binding to access the raw methods on -} - -// YVaultsV3APROracleTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type YVaultsV3APROracleTransactorRaw struct { - Contract *YVaultsV3APROracleTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewYVaultsV3APROracle creates a new instance of YVaultsV3APROracle, bound to a specific deployed contract. -func NewYVaultsV3APROracle(address common.Address, backend bind.ContractBackend) (*YVaultsV3APROracle, error) { - contract, err := bindYVaultsV3APROracle(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &YVaultsV3APROracle{YVaultsV3APROracleCaller: YVaultsV3APROracleCaller{contract: contract}, YVaultsV3APROracleTransactor: YVaultsV3APROracleTransactor{contract: contract}, YVaultsV3APROracleFilterer: YVaultsV3APROracleFilterer{contract: contract}}, nil -} - -// NewYVaultsV3APROracleCaller creates a new read-only instance of YVaultsV3APROracle, bound to a specific deployed contract. -func NewYVaultsV3APROracleCaller(address common.Address, caller bind.ContractCaller) (*YVaultsV3APROracleCaller, error) { - contract, err := bindYVaultsV3APROracle(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &YVaultsV3APROracleCaller{contract: contract}, nil -} - -// NewYVaultsV3APROracleTransactor creates a new write-only instance of YVaultsV3APROracle, bound to a specific deployed contract. -func NewYVaultsV3APROracleTransactor(address common.Address, transactor bind.ContractTransactor) (*YVaultsV3APROracleTransactor, error) { - contract, err := bindYVaultsV3APROracle(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &YVaultsV3APROracleTransactor{contract: contract}, nil -} - -// NewYVaultsV3APROracleFilterer creates a new log filterer instance of YVaultsV3APROracle, bound to a specific deployed contract. -func NewYVaultsV3APROracleFilterer(address common.Address, filterer bind.ContractFilterer) (*YVaultsV3APROracleFilterer, error) { - contract, err := bindYVaultsV3APROracle(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &YVaultsV3APROracleFilterer{contract: contract}, nil -} - -// bindYVaultsV3APROracle binds a generic wrapper to an already deployed contract. -func bindYVaultsV3APROracle(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := YVaultsV3APROracleMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_YVaultsV3APROracle *YVaultsV3APROracleRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _YVaultsV3APROracle.Contract.YVaultsV3APROracleCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_YVaultsV3APROracle *YVaultsV3APROracleRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _YVaultsV3APROracle.Contract.YVaultsV3APROracleTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_YVaultsV3APROracle *YVaultsV3APROracleRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _YVaultsV3APROracle.Contract.YVaultsV3APROracleTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_YVaultsV3APROracle *YVaultsV3APROracleCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _YVaultsV3APROracle.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_YVaultsV3APROracle *YVaultsV3APROracleTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _YVaultsV3APROracle.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_YVaultsV3APROracle *YVaultsV3APROracleTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _YVaultsV3APROracle.Contract.contract.Transact(opts, method, params...) -} - -// GetCurrentApr is a free data retrieval call binding the contract method 0x59d8703d. -// -// Solidity: function getCurrentApr(address _vault) view returns(uint256 apr) -func (_YVaultsV3APROracle *YVaultsV3APROracleCaller) GetCurrentApr(opts *bind.CallOpts, _vault common.Address) (*big.Int, error) { - var out []interface{} - err := _YVaultsV3APROracle.contract.Call(opts, &out, "getCurrentApr", _vault) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetCurrentApr is a free data retrieval call binding the contract method 0x59d8703d. -// -// Solidity: function getCurrentApr(address _vault) view returns(uint256 apr) -func (_YVaultsV3APROracle *YVaultsV3APROracleSession) GetCurrentApr(_vault common.Address) (*big.Int, error) { - return _YVaultsV3APROracle.Contract.GetCurrentApr(&_YVaultsV3APROracle.CallOpts, _vault) -} - -// GetCurrentApr is a free data retrieval call binding the contract method 0x59d8703d. -// -// Solidity: function getCurrentApr(address _vault) view returns(uint256 apr) -func (_YVaultsV3APROracle *YVaultsV3APROracleCallerSession) GetCurrentApr(_vault common.Address) (*big.Int, error) { - return _YVaultsV3APROracle.Contract.GetCurrentApr(&_YVaultsV3APROracle.CallOpts, _vault) -} - -// GetExpectedApr is a free data retrieval call binding the contract method 0x8c236964. -// -// Solidity: function getExpectedApr(address _vault, int256 _delta) view returns(uint256 apr) -func (_YVaultsV3APROracle *YVaultsV3APROracleCaller) GetExpectedApr(opts *bind.CallOpts, _vault common.Address, _delta *big.Int) (*big.Int, error) { - var out []interface{} - err := _YVaultsV3APROracle.contract.Call(opts, &out, "getExpectedApr", _vault, _delta) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetExpectedApr is a free data retrieval call binding the contract method 0x8c236964. -// -// Solidity: function getExpectedApr(address _vault, int256 _delta) view returns(uint256 apr) -func (_YVaultsV3APROracle *YVaultsV3APROracleSession) GetExpectedApr(_vault common.Address, _delta *big.Int) (*big.Int, error) { - return _YVaultsV3APROracle.Contract.GetExpectedApr(&_YVaultsV3APROracle.CallOpts, _vault, _delta) -} - -// GetExpectedApr is a free data retrieval call binding the contract method 0x8c236964. -// -// Solidity: function getExpectedApr(address _vault, int256 _delta) view returns(uint256 apr) -func (_YVaultsV3APROracle *YVaultsV3APROracleCallerSession) GetExpectedApr(_vault common.Address, _delta *big.Int) (*big.Int, error) { - return _YVaultsV3APROracle.Contract.GetExpectedApr(&_YVaultsV3APROracle.CallOpts, _vault, _delta) -} - -// GetStrategyApr is a free data retrieval call binding the contract method 0x4d060e36. -// -// Solidity: function getStrategyApr(address _strategy, int256 _debtChange) view returns(uint256) -func (_YVaultsV3APROracle *YVaultsV3APROracleCaller) GetStrategyApr(opts *bind.CallOpts, _strategy common.Address, _debtChange *big.Int) (*big.Int, error) { - var out []interface{} - err := _YVaultsV3APROracle.contract.Call(opts, &out, "getStrategyApr", _strategy, _debtChange) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetStrategyApr is a free data retrieval call binding the contract method 0x4d060e36. -// -// Solidity: function getStrategyApr(address _strategy, int256 _debtChange) view returns(uint256) -func (_YVaultsV3APROracle *YVaultsV3APROracleSession) GetStrategyApr(_strategy common.Address, _debtChange *big.Int) (*big.Int, error) { - return _YVaultsV3APROracle.Contract.GetStrategyApr(&_YVaultsV3APROracle.CallOpts, _strategy, _debtChange) -} - -// GetStrategyApr is a free data retrieval call binding the contract method 0x4d060e36. -// -// Solidity: function getStrategyApr(address _strategy, int256 _debtChange) view returns(uint256) -func (_YVaultsV3APROracle *YVaultsV3APROracleCallerSession) GetStrategyApr(_strategy common.Address, _debtChange *big.Int) (*big.Int, error) { - return _YVaultsV3APROracle.Contract.GetStrategyApr(&_YVaultsV3APROracle.CallOpts, _strategy, _debtChange) -} - -// Oracles is a free data retrieval call binding the contract method 0xaddd5099. -// -// Solidity: function oracles(address ) view returns(address) -func (_YVaultsV3APROracle *YVaultsV3APROracleCaller) Oracles(opts *bind.CallOpts, arg0 common.Address) (common.Address, error) { - var out []interface{} - err := _YVaultsV3APROracle.contract.Call(opts, &out, "oracles", arg0) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Oracles is a free data retrieval call binding the contract method 0xaddd5099. -// -// Solidity: function oracles(address ) view returns(address) -func (_YVaultsV3APROracle *YVaultsV3APROracleSession) Oracles(arg0 common.Address) (common.Address, error) { - return _YVaultsV3APROracle.Contract.Oracles(&_YVaultsV3APROracle.CallOpts, arg0) -} - -// Oracles is a free data retrieval call binding the contract method 0xaddd5099. -// -// Solidity: function oracles(address ) view returns(address) -func (_YVaultsV3APROracle *YVaultsV3APROracleCallerSession) Oracles(arg0 common.Address) (common.Address, error) { - return _YVaultsV3APROracle.Contract.Oracles(&_YVaultsV3APROracle.CallOpts, arg0) -} - -// WeightedApr is a free data retrieval call binding the contract method 0xf753dd5c. -// -// Solidity: function weightedApr(address _strategy) view returns(uint256) -func (_YVaultsV3APROracle *YVaultsV3APROracleCaller) WeightedApr(opts *bind.CallOpts, _strategy common.Address) (*big.Int, error) { - var out []interface{} - err := _YVaultsV3APROracle.contract.Call(opts, &out, "weightedApr", _strategy) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// WeightedApr is a free data retrieval call binding the contract method 0xf753dd5c. -// -// Solidity: function weightedApr(address _strategy) view returns(uint256) -func (_YVaultsV3APROracle *YVaultsV3APROracleSession) WeightedApr(_strategy common.Address) (*big.Int, error) { - return _YVaultsV3APROracle.Contract.WeightedApr(&_YVaultsV3APROracle.CallOpts, _strategy) -} - -// WeightedApr is a free data retrieval call binding the contract method 0xf753dd5c. -// -// Solidity: function weightedApr(address _strategy) view returns(uint256) -func (_YVaultsV3APROracle *YVaultsV3APROracleCallerSession) WeightedApr(_strategy common.Address) (*big.Int, error) { - return _YVaultsV3APROracle.Contract.WeightedApr(&_YVaultsV3APROracle.CallOpts, _strategy) -} - -// SetOracle is a paid mutator transaction binding the contract method 0x5c38eb3a. -// -// Solidity: function setOracle(address _strategy, address _oracle) returns() -func (_YVaultsV3APROracle *YVaultsV3APROracleTransactor) SetOracle(opts *bind.TransactOpts, _strategy common.Address, _oracle common.Address) (*types.Transaction, error) { - return _YVaultsV3APROracle.contract.Transact(opts, "setOracle", _strategy, _oracle) -} - -// SetOracle is a paid mutator transaction binding the contract method 0x5c38eb3a. -// -// Solidity: function setOracle(address _strategy, address _oracle) returns() -func (_YVaultsV3APROracle *YVaultsV3APROracleSession) SetOracle(_strategy common.Address, _oracle common.Address) (*types.Transaction, error) { - return _YVaultsV3APROracle.Contract.SetOracle(&_YVaultsV3APROracle.TransactOpts, _strategy, _oracle) -} - -// SetOracle is a paid mutator transaction binding the contract method 0x5c38eb3a. -// -// Solidity: function setOracle(address _strategy, address _oracle) returns() -func (_YVaultsV3APROracle *YVaultsV3APROracleTransactorSession) SetOracle(_strategy common.Address, _oracle common.Address) (*types.Transaction, error) { - return _YVaultsV3APROracle.Contract.SetOracle(&_YVaultsV3APROracle.TransactOpts, _strategy, _oracle) -} diff --git a/common/env/chain.arbitrum.go b/common/env/chain.arbitrum.go index e6669b234..0896e77be 100644 --- a/common/env/chain.arbitrum.go +++ b/common/env/chain.arbitrum.go @@ -30,10 +30,6 @@ var ARBITRUM = TChain{ Address: common.HexToAddress(`0x0e5b46E4b2a05fd53F5a4cD974eb98a9a613bcb7`), Block: 30385403, }, - APROracleContract: TContractData{ - Address: common.HexToAddress(`0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92`), - Block: 265347717, - }, StakingRewardRegistry: []TContractData{ { Address: common.HexToAddress(`0x26d8EA1d8759d0F9abBcf8181b1fD5D3635daD69`), diff --git a/common/env/chain.base.go b/common/env/chain.base.go index d0881c6bc..a3d666d6a 100644 --- a/common/env/chain.base.go +++ b/common/env/chain.base.go @@ -67,10 +67,6 @@ var BASE = TChain{ Label: `YEARN`, }, }, - APROracleContract: TContractData{ - Address: common.HexToAddress(`0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92`), - Block: 63167152, - }, ExtraVaults: []models.TVaultsFromRegistry{}, BlacklistedVaults: []common.Address{}, ExtraTokens: []common.Address{ diff --git a/common/env/chain.ethereum.go b/common/env/chain.ethereum.go index ad39d95ef..bb8ed431c 100644 --- a/common/env/chain.ethereum.go +++ b/common/env/chain.ethereum.go @@ -34,10 +34,6 @@ var ETHEREUM = TChain{ Address: common.HexToAddress(`0x8ee392a4787397126C163Cb9844d7c447da419D8`), Block: 14166636, }, - APROracleContract: TContractData{ - Address: common.HexToAddress(`0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92`), - Block: 19070394, - }, ExtraStakingContracts: []TExtraStakingContracts{ { VaultAddress: common.HexToAddress(`0xe24BA27551aBE96Ca401D39761cA2319Ea14e3CB`), diff --git a/common/env/chain.gnosis.go b/common/env/chain.gnosis.go index 341d51d2b..9306deeca 100644 --- a/common/env/chain.gnosis.go +++ b/common/env/chain.gnosis.go @@ -24,7 +24,6 @@ var GNOSIS = TChain{ Block: 821923, }, PartnerContract: TContractData{}, - APROracleContract: TContractData{}, Coin: models.TERC20Token{ Address: DEFAULT_COIN_ADDRESS, UnderlyingTokensAddresses: []common.Address{}, diff --git a/common/env/chain.katana.go b/common/env/chain.katana.go index 8fad2bb49..3c44473aa 100644 --- a/common/env/chain.katana.go +++ b/common/env/chain.katana.go @@ -63,10 +63,6 @@ var KATANA = TChain{ Label: `PUBLIC_ERC4626`, }, }, - APROracleContract: TContractData{ - Address: common.HexToAddress(`0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92`), - Block: 2237016, - }, ExtraVaults: []models.TVaultsFromRegistry{}, BlacklistedVaults: []common.Address{}, ExtraTokens: []common.Address{}, diff --git a/common/env/chain.polygon.go b/common/env/chain.polygon.go index 1b9d44fbf..751c42d04 100644 --- a/common/env/chain.polygon.go +++ b/common/env/chain.polygon.go @@ -23,10 +23,6 @@ var POLYGON = TChain{ Address: common.HexToAddress(`0xca11bde05977b3631167028862be2a173976ca11`), Block: 25770160, }, - APROracleContract: TContractData{ - Address: common.HexToAddress(`0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92`), - Block: 52516525, - }, Coin: models.TERC20Token{ Address: DEFAULT_COIN_ADDRESS, UnderlyingTokensAddresses: []common.Address{}, diff --git a/common/env/chains.go b/common/env/chains.go index 084c4dc4f..8cdf4b5a2 100644 --- a/common/env/chains.go +++ b/common/env/chains.go @@ -74,7 +74,6 @@ type TChain struct { MulticallContract TContractData YBribeV3Contract TContractData PartnerContract TContractData - APROracleContract TContractData Coin models.TERC20Token StakingRewardRegistry []TContractData Registries []TContractData diff --git a/docs/apr-oracle-integration.md b/docs/apr-oracle-integration.md new file mode 100644 index 000000000..c0b96ffd0 --- /dev/null +++ b/docs/apr-oracle-integration.md @@ -0,0 +1,34 @@ +# APR Oracle Integration (Kong) + +As of version `yDaemon v3.0.0+`, the integration with the on-chain APR Oracle contract for V3 vaults has been replaced with a direct integration with Kong's GraphQL API. + +## Overview + +Previously, `yDaemon` calculated forward-looking APRs for V3 vaults by making RPC calls to a specific Oracle smart contract. This dependency has been removed in favor of fetching pre-calculated oracle data directly from Yearn's data aggregator, **Kong**. + +## Data Source + +The `performance.oracle` field from Kong's GraphQL API is now the single source of truth for: +- **Oracle APR**: The annualized rate based on recent performance. +- **Oracle APY**: The annualized yield (compounded). + +## Implementation Details + +- **Internal Logic**: The `forward.v3.go` process queries the internal storage (populated by the Kong indexer) instead of computing values on-chain. +- **Strategies**: Strategy-level APRs (`NetAPR`) for V3 also utilize this data source via `GetCurrentStrategyAPR` or the vault-level fallback, ensuring consistency. +- **Fallback**: If Kong data is unavailable or null, the system gracefully defaults to zero values, preventing API crashes. + +## API Response + +The external API response structure for vaults remains unchanged to ensure backward compatibility. The `apr.forwardAPR` object is populated with the data retrieved from Kong. + +```json +"forwardAPR": { + "type": "v3:onchainOracle", + "netAPR": 0.045, // Sourced from Kong + "composite": { + "v3OracleCurrentAPR": 0.045, + "v3OracleStratRatioAPR": 0.045 + } +} +``` diff --git a/internal/fetcher/strategies.go b/internal/fetcher/strategies.go index 4b33ba771..7d846f5d9 100755 --- a/internal/fetcher/strategies.go +++ b/internal/fetcher/strategies.go @@ -100,16 +100,6 @@ func getStrategyAPR(chainID uint64, versionMajor string, strategy models.TStrate ** For earlier versions: Only try to get current APR ******************************************************************************************/ if versionMajor == `3` { - if forwardAPR, err := apr.ComputeForwardStrategyAPR(strategy); err == nil { - netAPR = forwardAPR - aprType = models.APRTypeForward - } else if currentAPR, err := apr.GetCurrentStrategyAPR(chainID, strategy.Address.Hex()); err == nil { - netAPR = currentAPR - aprType = models.APRTypeCurrent - } else { - return netAPR, aprType, errors.New(`Error while computing forward APR for ` + strategy.Address.Hex() + ` | ` + strategy.VaultAddress.Hex() + `: ` + err.Error()) - } - } else { if currentAPR, err := apr.GetCurrentStrategyAPR(chainID, strategy.Address.Hex()); err == nil { netAPR = currentAPR aprType = models.APRTypeCurrent diff --git a/internal/indexer/indexer.kong.go b/internal/indexer/indexer.kong.go index 0d30ffa16..6e6522c78 100644 --- a/internal/indexer/indexer.kong.go +++ b/internal/indexer/indexer.kong.go @@ -67,13 +67,23 @@ func IndexNewVaults(chainID uint64) map[common.Address]models.TVaultsFromRegistr }) } + // Extract performance data from Kong response (oracle APR/APY) + performance := models.TKongPerformance{} + if data.Vault.Performance != nil { + performance.Oracle = models.TKongOracle{ + Apr: data.Vault.Performance.Oracle.Apr, + Apy: data.Vault.Performance.Oracle.Apy, + } + } + kongSchema := models.TKongVaultSchema{ - ManagementFee: data.Vault.GetManagementFee(), - PerformanceFee: data.Vault.GetPerformanceFee(), - APY: data.APY, - Debts: debts, - TVL: data.Vault.GetTVL(), - TotalAssets: data.TotalAssets, + ManagementFee: data.Vault.GetManagementFee(), + PerformanceFee: data.Vault.GetPerformanceFee(), + APY: data.APY, + Performance: performance, + Debts: debts, + TVL: data.Vault.GetTVL(), + TotalAssets: data.TotalAssets, StrategyAddresses: data.Vault.GetStrategies(), } storage.StoreKongVaultData(chainID, vaultAddr, kongSchema) diff --git a/internal/kong/client.go b/internal/kong/client.go index 12a33a3ac..0702d3c70 100644 --- a/internal/kong/client.go +++ b/internal/kong/client.go @@ -72,6 +72,15 @@ type KongFees struct { PerformanceFee float64 `json:"performanceFee"` } +type KongOracle struct { + Apr *float64 `json:"apr"` // Float or null + Apy *float64 `json:"apy"` // Float or null +} + +type KongPerformance struct { + Oracle KongOracle `json:"oracle"` +} + type KongVault struct { Address string `json:"address"` ChainID int `json:"chainId"` @@ -84,6 +93,7 @@ type KongVault struct { Strategies []string `json:"strategies"` Debts []KongDebt `json:"debts"` TVL *KongTVL `json:"tvl"` + Performance *KongPerformance `json:"performance"` // Oracle APR/APY data APY models.KongAPY `json:"apy"` TotalAssets *bigNumber.Int `json:"totalAssets"` ManagementFee *string `json:"managementFee"` // BigInt as string (basis points) @@ -200,6 +210,12 @@ func (c *Client) FetchVaultsForChain(ctx context.Context, chainID uint64) ([]Kon managementFee performanceFee } + performance { + oracle { + apr + apy + } + } apy { pricePerShare weeklyNet @@ -281,6 +297,12 @@ func (c *Client) FetchAllVaults(ctx context.Context) (map[uint64][]KongVault, er managementFee performanceFee } + performance { + oracle { + apr + apy + } + } apy { pricePerShare weeklyNet diff --git a/internal/models/vaults.go b/internal/models/vaults.go index e5787842e..7b2e1d0a5 100644 --- a/internal/models/vaults.go +++ b/internal/models/vaults.go @@ -316,6 +316,15 @@ type KongAPY struct { Decimals uint64 `json:"decimals"` // Token decimals for PPS normalization } +type TKongOracle struct { + Apr *float64 `json:"apr"` // Float or null + Apy *float64 `json:"apy"` // Float or null +} + +type TKongPerformance struct { + Oracle TKongOracle `json:"oracle"` +} + type TKongVaultSchema struct { Hook struct { Fees struct { @@ -327,11 +336,12 @@ type TKongVaultSchema struct { ManagementFee CoercibleUint64 `json:"managementFee"` PerformanceFee CoercibleUint64 `json:"performanceFee"` } `json:"snapshot"` - TVL float64 `json:"tvl"` // TVL from Kong (tvl.close field) - Debts []TKongDebt `json:"debts"` // Debts array from Kong - TotalAssets *bigNumber.Int `json:"totalAssets"` // Total assets from Kong - APY KongAPY `json:"apy"` - ManagementFee uint64 `json:"managementFee"` // Basis points from Kong (direct field takes priority) - PerformanceFee uint64 `json:"performanceFee"` // Basis points from Kong (direct field takes priority) + TVL float64 `json:"tvl"` // TVL from Kong (tvl.close field) + Debts []TKongDebt `json:"debts"` // Debts array from Kong + TotalAssets *bigNumber.Int `json:"totalAssets"` // Total assets from Kong + Performance TKongPerformance `json:"performance"` // Oracle APR/APY data from Kong + APY KongAPY `json:"apy"` + ManagementFee uint64 `json:"managementFee"` // Basis points from Kong (direct field takes priority) + PerformanceFee uint64 `json:"performanceFee"` // Basis points from Kong (direct field takes priority) StrategyAddresses []common.Address `json:"strategyAddresses"` // Strategy addresses from Kong } diff --git a/internal/storage/elem.vaults.go b/internal/storage/elem.vaults.go index 233d7cd6e..b6b75864e 100644 --- a/internal/storage/elem.vaults.go +++ b/internal/storage/elem.vaults.go @@ -460,4 +460,16 @@ func GetKongTotalAssets(chainID uint64, vaultAddress common.Address) (*bigNumber return nil, false } return data.TotalAssets, true +} + +/************************************************************************************************** +** GetKongOracleAPY retrieves oracle APR/APY from Kong data for a vault +** Returns (apr, apy, exists) where apr and apy are *float64 (may be nil) +**************************************************************************************************/ +func GetKongOracleAPY(chainID uint64, vaultAddress common.Address) (*float64, *float64, bool) { + data, ok := GetKongVaultData(chainID, vaultAddress) + if !ok { + return nil, nil, false + } + return data.Performance.Oracle.Apr, data.Performance.Oracle.Apy, true } \ No newline at end of file diff --git a/processes/apr/forward.strategy.go b/processes/apr/forward.strategy.go deleted file mode 100644 index a68556e05..000000000 --- a/processes/apr/forward.strategy.go +++ /dev/null @@ -1,61 +0,0 @@ -package apr - -import ( - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/yearn/ydaemon/common/bigNumber" - "github.com/yearn/ydaemon/common/contracts" - "github.com/yearn/ydaemon/common/env" - "github.com/yearn/ydaemon/common/ethereum" - "github.com/yearn/ydaemon/common/helpers" - "github.com/yearn/ydaemon/internal/models" -) - -func ComputeForwardStrategyAPR(strategy models.TStrategy) (*bigNumber.Float, error) { - oracleAPR := bigNumber.NewFloat(0) - chain, ok := env.GetChain(strategy.ChainID) - if !ok { - return nil, errors.New(`chain not found`) - } - oracleContract := chain.APROracleContract.Address - if oracleContract == common.HexToAddress(``) { - return nil, errors.New(`oracle not found`) - } - oracle, err := contracts.NewYVaultsV3APROracleCaller(oracleContract, ethereum.GetRPC(strategy.ChainID)) - if err != nil { - return nil, err - } - - /********************************************************************************************** - ** If the vault is a single strategy vault, we can use the oracle directly to get the APR of - ** the vault as expected APR - **********************************************************************************************/ - var hasError error - expected, err := oracle.GetStrategyApr(nil, strategy.Address, big.NewInt(0)) - if err == nil { - oracleAPR = helpers.ToNormalizedAmount(bigNumber.SetInt(expected), 18) - } else { - hasError = err - } - - if hasError != nil || oracleAPR.IsZero() { - expected, newErr := oracle.GetCurrentApr(nil, strategy.VaultAddress) - err = newErr - if newErr == nil { - oracleAPR = helpers.ToNormalizedAmount(bigNumber.SetInt(expected), 18) - } else { - return nil, err - } - } - - /********************************************************************************************** - ** Define which APR we want to use as "Net APR". - **********************************************************************************************/ - primaryAPR := oracleAPR - primaryAPRFloat64, _ := primaryAPR.Float64() - primaryAPY := bigNumber.NewFloat(0).SetFloat64(convertFloatAPRToAPY(primaryAPRFloat64, 52)) - - return primaryAPY, nil -} diff --git a/processes/apr/forward.v3.go b/processes/apr/forward.v3.go index 4bd80ee21..68919b408 100644 --- a/processes/apr/forward.v3.go +++ b/processes/apr/forward.v3.go @@ -1,17 +1,12 @@ package apr import ( - "math/big" "strings" - "github.com/ethereum/go-ethereum/common" "github.com/yearn/ydaemon/common/bigNumber" - "github.com/yearn/ydaemon/common/contracts" - "github.com/yearn/ydaemon/common/env" - "github.com/yearn/ydaemon/common/ethereum" - "github.com/yearn/ydaemon/common/helpers" "github.com/yearn/ydaemon/common/logs" "github.com/yearn/ydaemon/internal/models" + "github.com/yearn/ydaemon/internal/storage" ) func isV3Vault(vault models.TVault) bool { @@ -23,47 +18,51 @@ func computeVaultV3ForwardAPY( vault models.TVault, allStrategiesForVault map[string]models.TStrategy, ) TForwardAPY { - oracleAPR := bigNumber.NewFloat(0) - chain, ok := env.GetChain(vault.ChainID) - if !ok { - return TForwardAPY{} - } - oracleContract := chain.APROracleContract.Address - if oracleContract == common.HexToAddress(``) { - return TForwardAPY{} - } - oracle, err := contracts.NewYVaultsV3APROracleCaller(oracleContract, ethereum.GetRPC(vault.ChainID)) - if err != nil { - logs.Error(err) - return TForwardAPY{} - } + chainID := vault.ChainID /********************************************************************************************** - ** Use the oracle to get the APR of the vault. The oracle automatically handles: - ** - Single strategy vaults: Returns strategy APR - ** - Multi-strategy vaults: Returns weighted average with performance fees applied + ** Fetch Kong oracle APR/APY data (single source of truth) + ** Kong provides pre-calculated oracle APR and APY from daily timeseries hook **********************************************************************************************/ - expected, err := oracle.GetStrategyApr(nil, vault.Address, big.NewInt(0)) - if err != nil { - logs.Error(`GetStrategyApr failed for vault ` + vault.Address.Hex() + `: ` + err.Error()) - return TForwardAPY{} + _, oracleAPY, ok := storage.GetKongOracleAPY(chainID, vault.Address) + + if !ok { + logs.Error("Kong oracle data missing for vault %s on chain %d - Kong source unavailable", vault.Address.Hex(), chainID) + return TForwardAPY{ + Type: `v3:onchainOracle`, + NetAPY: bigNumber.NewFloat(0), + Composite: TCompositeData{ + V3OracleCurrentAPR: bigNumber.NewFloat(0), + V3OracleStratRatioAPR: bigNumber.NewFloat(0), + }, + } + } + + // Handle nil values (Kong returns null for vaults without oracle data) + if oracleAPY == nil { + logs.Warning("Kong oracle APY is null for vault %s on chain %d - vault may not have oracle configured", vault.Address.Hex(), chainID) + return TForwardAPY{ + Type: `v3:onchainOracle`, + NetAPY: bigNumber.NewFloat(0), + Composite: TCompositeData{ + V3OracleCurrentAPR: bigNumber.NewFloat(0), + V3OracleStratRatioAPR: bigNumber.NewFloat(0), + }, + } } - oracleAPR = helpers.ToNormalizedAmount(bigNumber.SetInt(expected), 18) /********************************************************************************************** - ** Use the oracle APR as the primary APR (no manual calculation needed) + ** Use Kong's pre-calculated oracle APY + ** Kong already converts APR to APY using weekly compounding (52 periods/year) **********************************************************************************************/ - primaryAPR := oracleAPR - - primaryAPRFloat64, _ := primaryAPR.Float64() - primaryAPY := bigNumber.NewFloat(0).SetFloat64(convertFloatAPRToAPY(primaryAPRFloat64, 52)) + primaryAPY := bigNumber.NewFloat(*oracleAPY) return TForwardAPY{ Type: `v3:onchainOracle`, NetAPY: primaryAPY, Composite: TCompositeData{ V3OracleCurrentAPR: primaryAPY, - V3OracleStratRatioAPR: bigNumber.NewFloat(0), + V3OracleStratRatioAPR: bigNumber.NewFloat(0), // Not used with Kong oracle }, } }