diff --git a/docs/developers/addresses/core-contracts.md b/docs/developers/addresses/core-contracts.md index 23c09e61c..f415af520 100644 --- a/docs/developers/addresses/core-contracts.md +++ b/docs/developers/addresses/core-contracts.md @@ -78,7 +78,6 @@ See all stYFI contracts [on this page](./styfi-contracts.md) | --------------------- | ------------------------------------------ | | kChad multisig | [0xe6ad5A88f5da0F276C903d9Ac2647A937c917162](https://katanascan.com/address/0xe6ad5A88f5da0F276C903d9Ac2647A937c917162) | | Strategist multisig | [0xBe7c7efc1ef3245d37E3157F76A512108D6D7aE6](https://katanascan.com/address/0xBe7c7efc1ef3245d37E3157F76A512108D6D7aE6) | -| V3 multisig | [0x33333333D5eFb92f19a5F94a43456b3cec2797AE](https://katanascan.com/address/0x33333333D5eFb92f19a5F94a43456b3cec2797AE) | | Timelock | [0x88Ba032be87d5EF1fbE87336B7090767F367BF73](https://katanascan.com/address/0x88Ba032be87d5EF1fbE87336B7090767F367BF73) | | Timelock Executor | [0xF8f60BF9456A6e0141149Db2DD6f02C60da5779B](https://katanascan.com/address/0xF8f60BF9456A6e0141149Db2DD6f02C60da5779B) | diff --git a/docs/developers/addresses/v3-contracts.md b/docs/developers/addresses/v3-contracts.md index b86af9932..05f684003 100644 --- a/docs/developers/addresses/v3-contracts.md +++ b/docs/developers/addresses/v3-contracts.md @@ -66,7 +66,9 @@ All generic periphery contracts and factories can be retrieved on chain from the | **Debt Allocator Factory**
| | | **Registry Factory**
| | | **Splitter Factory**
| | +| **Auction Registry**
| | | **Auction Factory**
| | +| **Dumper**
| | | **Keeper**
| | | **Base Fee Provider**
| | @@ -84,6 +86,7 @@ These addresses are consistent across all EVM chains. | Name / ENS | Contract Address | | ---------------------- | ---------------------- | +| **V3 Deployer Multisig**
registry.v3.ychad.eth | | | **Current V3 Registry**
registry.v3.ychad.eth | | | **Legacy V3 Registry**
| | @@ -95,6 +98,7 @@ Ethereum-specific Yearn addresses | ---------------------- | ---------------------- | | **Role Manager**
role-manager.v3.ychad.eth | | | **Accountant**
accountant.v3.ychad.eth | | +| **Debt Allocator**
| | ### Optimism (10) Addresses @@ -122,6 +126,7 @@ Base-specific Yearn addresses | ---------------------- | ---------------------- | | **Role Manager**
| | | **Accountant**
| | +| **Debt Allocator**
| | ### Arbitrum (42161) Addresses @@ -131,6 +136,7 @@ Arbitrum-specific Yearn addresses | ---------------------- | ---------------------- | | **Role Manager**
| | | **Accountant**
| | +| **Debt Allocator**
| | ### Katana (747474) Addresses diff --git a/docs/developers/smart-contracts/V3/Periphery/AuctionFactory.md b/docs/developers/smart-contracts/V3/Periphery/AuctionFactory.md new file mode 100644 index 000000000..40fe43dad --- /dev/null +++ b/docs/developers/smart-contracts/V3/Periphery/AuctionFactory.md @@ -0,0 +1,199 @@ + +# AuctionFactory + +[Git Source](https://github.com/yearn/tokenized-strategy-periphery/blob/c0dfe4a563a45efb72718547e840429b3a6092e6/src/Auctions/AuctionFactory.sol) + +**Inherits:** ClonableCreate2 + +**Title:** +AuctionFactory + +Deploy a new Auction. + +## State Variables + +### DEFAULT_STARTING_PRICE + +The amount to start the auction with. + +```solidity +uint256 public constant DEFAULT_STARTING_PRICE = 1_000_000 +``` + +### auctions + +Full array of all auctions deployed through this factory. + +```solidity +address[] public auctions +``` + +## Functions + +### constructor + +```solidity +constructor() ; +``` + +### version + +```solidity +function version() external pure returns (string memory); +``` + +### createNewAuction + +Creates a new auction contract. + +```solidity +function createNewAuction(address _want) external returns (address); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_want`|`address`|Address of the token users will bid with.| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`address`|_newAuction Address of the newly created auction contract.| + +### createNewAuction + +Creates a new auction contract. + +```solidity +function createNewAuction(address _want, address _receiver) external returns (address); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_want`|`address`|Address of the token users will bid with.| +|`_receiver`|`address`|Address that will receive the funds in the auction.| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`address`|_newAuction Address of the newly created auction contract.| + +### createNewAuction + +Creates a new auction contract. + +```solidity +function createNewAuction(address _want, address _receiver, address _governance) external returns (address); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_want`|`address`|Address of the token users will bid with.| +|`_receiver`|`address`|Address that will receive the funds in the auction.| +|`_governance`|`address`|Address allowed to enable and disable auctions.| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`address`|_newAuction Address of the newly created auction contract.| + +### createNewAuction + +Creates a new auction contract. + +```solidity +function createNewAuction(address _want, address _receiver, address _governance, uint256 _startingPrice) + external + returns (address); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_want`|`address`|Address of the token users will bid with.| +|`_receiver`|`address`|Address that will receive the funds in the auction.| +|`_governance`|`address`|Address allowed to enable and disable auctions.| +|`_startingPrice`|`uint256`|Starting price for the auction (no decimals). NOTE: The starting price should be without decimals (1k == 1_000).| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`address`|_newAuction Address of the newly created auction contract.| + +### createNewAuction + +Creates a new auction contract. + +```solidity +function createNewAuction( + address _want, + address _receiver, + address _governance, + uint256 _startingPrice, + bytes32 _salt +) external returns (address); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_want`|`address`|Address of the token users will bid with.| +|`_receiver`|`address`|Address that will receive the funds in the auction.| +|`_governance`|`address`|Address allowed to enable and disable auctions.| +|`_startingPrice`|`uint256`|Starting price for the auction (no decimals).| +|`_salt`|`bytes32`|The salt to use for deterministic deployment.| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`address`|_newAuction Address of the newly created auction contract.| + +### _createNewAuction + +Deploys and initializes a new Auction + +```solidity +function _createNewAuction( + address _want, + address _receiver, + address _governance, + uint256 _startingPrice, + bytes32 _salt +) internal returns (address _newAuction); +``` + +### getAllAuctions + +Get the full list of auctions deployed through this factory. + +```solidity +function getAllAuctions() external view returns (address[] memory); +``` + +### numberOfAuctions + +Get the total number of auctions deployed through this factory. + +```solidity +function numberOfAuctions() external view returns (uint256); +``` + +## Events + +### DeployedNewAuction + +```solidity +event DeployedNewAuction(address indexed auction, address indexed want); +``` diff --git a/docs/developers/smart-contracts/V3/Periphery/AuctionRegistry.md b/docs/developers/smart-contracts/V3/Periphery/AuctionRegistry.md new file mode 100644 index 000000000..7305d8c67 --- /dev/null +++ b/docs/developers/smart-contracts/V3/Periphery/AuctionRegistry.md @@ -0,0 +1,223 @@ + +# AuctionRegistry + +[Git Source](https://github.com/yearn/tokenized-strategy-periphery/blob/c0dfe4a563a45efb72718547e840429b3a6092e6/src/Auctions/AuctionRegistry.sol) + +**Inherits:** Governance2Step + +**Title:** +AuctionRegistry + +Registry contract that manages released and endorsed auction factory addresses + +Provides on-chain discovery and verification of official auction factories + +## State Variables + +### factories + +Array of all registered factories + +```solidity +address[] public factories +``` + +### factoryInfo + +Mapping from factory address to its index in the factories array + +```solidity +mapping(address => FactoryInfo) public factoryInfo +``` + +### versionToFactory + +Mapping from version string to factory address + +```solidity +mapping(string => address) public versionToFactory +``` + +## Functions + +### constructor + +Initialize the registry with known factory addresses + +```solidity +constructor(address _governance, address[] memory _knownFactories, string[] memory _versions) + Governance2Step(_governance); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_governance`|`address`|The address that will have governance rights| +|`_knownFactories`|`address[]`|Array of known factory addresses to register| +|`_versions`|`string[]`|Array of version strings corresponding to the factories| + +### getLatestFactory + +Get the latest endorsed auction factory address + +```solidity +function getLatestFactory() external view returns (address factory); +``` + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|`factory`|`address`|The address of the latest endorsed factory| + +### getFactory + +Get a factory by its version string + +```solidity +function getFactory(string memory _version) external view returns (address factory); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_version`|`string`|The version string of the factory| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|`factory`|`address`|The address of the factory| + +### getFactoryInfo + +Get factory information by address + +```solidity +function getFactoryInfo(address _factory) external view returns (FactoryInfo memory info); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_factory`|`address`|The address of the factory| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|`info`|`FactoryInfo`|The factory information struct| + +### getAllFactories + +Get all registered factories + +```solidity +function getAllFactories() external view returns (address[] memory); +``` + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`address[]`|All factory information| + +### numberOfFactories + +Get the total number of registered factories + +```solidity +function numberOfFactories() external view returns (uint256); +``` + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`uint256`|The number of registered factories| + +### isRegisteredFactory + +Check if a factory is endorsed + +```solidity +function isRegisteredFactory(address _factory) public view returns (bool); +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_factory`|`address`|The address to check| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`bool`|True if the factory is endorsed| + +### registerNewFactory + +Release a new factory + +```solidity +function registerNewFactory(address _factory, string memory _version) external onlyGovernance; +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_factory`|`address`|The address of the factory| +|`_version`|`string`|The version string of the factory| + +### retireFactory + +Revoke endorsement from a factory + +```solidity +function retireFactory(address _factory) external onlyGovernance; +``` + +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`_factory`|`address`|The address of the factory| + +### _registerFactory + +Internal function to register a factory + +```solidity +function _registerFactory(address _factory, string memory _version) internal; +``` + +## Events + +### FactoryRegistered + +```solidity +event FactoryRegistered(address indexed factory, string version, uint256 index); +``` + +### FactoryRetired + +```solidity +event FactoryRetired(address indexed factory); +``` + +## Structs + +### FactoryInfo + +```solidity +struct FactoryInfo { + string version; + uint256 index; + bool isRetired; +} +``` diff --git a/docs/developers/smart-contracts/V3/Periphery/Keeper.md b/docs/developers/smart-contracts/V3/Periphery/Keeper.md new file mode 100644 index 000000000..52c0ed082 --- /dev/null +++ b/docs/developers/smart-contracts/V3/Periphery/Keeper.md @@ -0,0 +1,37 @@ + +# Keeper + +[Git Source](https://github.com/yearn/vault-periphery/blob/bc4eee4051e3319427012e65296110bbdc00488d/src/Keeper.sol) + +**Title:** +Keeper + +To allow permissionless reporting on V3 vaults and strategies. +This will do low level calls so that in can be used without reverting +it the roles have not been set or the functions are not available. + +## Functions + +### report + +Reports on a strategy. + +```solidity +function report(address _strategy) external returns (uint256, uint256); +``` + +### tend + +Tends a strategy. + +```solidity +function tend(address _strategy) external; +``` + +### process_report + +Report strategy profits on a vault. + +```solidity +function process_report(address _vault, address _strategy) external returns (uint256, uint256); +``` diff --git a/docs/developers/v3/Integrating_v3.md b/docs/developers/v3/Integrating_v3.md index 19d60691e..1d88fc625 100644 --- a/docs/developers/v3/Integrating_v3.md +++ b/docs/developers/v3/Integrating_v3.md @@ -16,8 +16,6 @@ token.approve(vault, amount) vault.deposit(amount, receiver) ``` -There is also a [4626 Router](/developers/smart-contracts/V3/Periphery/Yearn4626Router) available to make multi-step user flows easier. - The max amount that a vault will accept from an address can be returned using the [`maxDeposit`](https://eips.ethereum.org/EIPS/eip-4626#maxdeposit) function. ### Withdrawals diff --git a/natspec/lib/tokenized-strategy-periphery b/natspec/lib/tokenized-strategy-periphery index f70e702c3..c0dfe4a56 160000 --- a/natspec/lib/tokenized-strategy-periphery +++ b/natspec/lib/tokenized-strategy-periphery @@ -1 +1 @@ -Subproject commit f70e702c378fa41e52c46acf3da8b4e90c6a0ff8 +Subproject commit c0dfe4a563a45efb72718547e840429b3a6092e6 diff --git a/natspec/lib/vault-periphery b/natspec/lib/vault-periphery index 329c63c18..bc4eee405 160000 --- a/natspec/lib/vault-periphery +++ b/natspec/lib/vault-periphery @@ -1 +1 @@ -Subproject commit 329c63c187d13c1e1443571238f6144b1ee0726f +Subproject commit bc4eee4051e3319427012e65296110bbdc00488d diff --git a/requirements.txt b/requirements.txt index ff32abfa1..cca8dfc34 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -asttokens==3.0.1 +asttokens==2.0.5 certifi==2025.11.12 charset-normalizer==3.4.4 idna==3.11 @@ -9,5 +9,5 @@ semantic-version==2.10.0 six==1.17.0 solc-select==1.1.0 urllib3==2.6.0 -vyper==0.4.3 +vyper==0.3.7 # ypricemagic==4.10.10 diff --git a/smartContracts.json b/smartContracts.json index 9235f1742..c718a0616 100644 --- a/smartContracts.json +++ b/smartContracts.json @@ -43,6 +43,18 @@ "type": "file", "git": "https://github.com/yearn/vault-periphery" }, + "Keeper.sol": { + "type": "file", + "git": "https://github.com/yearn/vault-periphery" + }, + "AuctionRegistry.sol": { + "type": "file", + "git": "https://github.com/yearn/tokenized-strategy-periphery" + }, + "AuctionFactory.sol": { + "type": "file", + "git": "https://github.com/yearn/tokenized-strategy-periphery" + }, "Auction.sol": { "type": "file", "git": "https://github.com/yearn/tokenized-strategy-periphery" diff --git a/src/ethereum/ABIs/accountantABI.ts b/src/ethereum/ABIs/accountantABI.ts new file mode 100644 index 000000000..6e5e66fb5 --- /dev/null +++ b/src/ethereum/ABIs/accountantABI.ts @@ -0,0 +1,9 @@ +export const accountantABI = [ + { + stateMutability: 'view', + type: 'function', + name: 'feeRecipient', + inputs: [], + outputs: [{ name: '', type: 'address' }], + }, +] as const diff --git a/src/ethereum/ABIs/auctionRegistryABI.ts b/src/ethereum/ABIs/auctionRegistryABI.ts new file mode 100644 index 000000000..1f0b37f9e --- /dev/null +++ b/src/ethereum/ABIs/auctionRegistryABI.ts @@ -0,0 +1,9 @@ +export const auctionRegistryABI = [ + { + stateMutability: 'view', + type: 'function', + name: 'getLatestFactory', + inputs: [], + outputs: [{ name: '', type: 'address' }], + }, +] as const diff --git a/src/ethereum/ABIs/index.ts b/src/ethereum/ABIs/index.ts index ab19c5d7e..e226bca5f 100644 --- a/src/ethereum/ABIs/index.ts +++ b/src/ethereum/ABIs/index.ts @@ -16,3 +16,5 @@ export * from './veyfiABI' export * from './yPoolsGenericGovernorABI' export * from './yPoolsInclusionVoteABI' export * from './gnosisSafeABI' +export * from './auctionRegistryABI' +export * from './accountantABI' diff --git a/src/ethereum/constants.ts b/src/ethereum/constants.ts index 2d46c00e0..49108bd23 100644 --- a/src/ethereum/constants.ts +++ b/src/ethereum/constants.ts @@ -185,7 +185,9 @@ export const protocolPeriphery = { aprOracle: '0x1981AD9F44F2EA9aDd2dC4AD7D075c102C70aF92', baseFeeProvider: '0xe0514dd71cfdc30147e76f65c30bdf60bfd437c3', commonReportTrigger: '0xf8dF17a35c88AbB25e83C92f9D293B4368b9D52D', - auctionFactory: '0xbC587a495420aBB71Bbd40A0e291B64e80117526', + auctionRegistry: '0x94F44706A61845a4f9e59c4Bc08cEA4503e48D12', + auctionFactory: '0xbA7FCb508c7195eE5AE823F37eE2c11D7ED52F8e', + dumper: '0x590Dd9399bB53f1085097399C3265C7137c1C4Cf', splitterFactory: '0xe28fCC9FB2998ba57754789F6666DAa8C815614D', registryFactory: '0x3A0fa8aac82aD94048098D6af6e8eB36c98816A1', debtAllocatorFactory: '0x03D43dF6FF894C848fC6F1A0a7E8a539Ef9A4C18', @@ -198,6 +200,7 @@ export const protocolPeriphery = { * Queried from the Yearn Role Manager */ export const yearnV3ContractsStable = { + v3Deployer: '0x33333333D5eFb92f19a5F94a43456b3cec2797AE', registryENS: 'registry.v3.ychad.eth', registry: '0xd40ecF29e001c76Dcc4cC0D9cd50520CE845B038', legacyRegistry1: '0xff31A1B020c868F6eA3f61Eb953344920EeCA3af', diff --git a/src/ethereum/v3Calls.ts b/src/ethereum/v3Calls.ts index 0be640a66..5cfcef677 100644 --- a/src/ethereum/v3Calls.ts +++ b/src/ethereum/v3Calls.ts @@ -5,6 +5,8 @@ import { v3VaultFactoryABI, yearnV3RoleManagerABI, v3VaultFactoryBlueprintABI, + auctionRegistryABI, + accountantABI, } from './ABIs' import { V3ReleaseDataMap } from './types' @@ -159,3 +161,39 @@ export const readYearnRoleManager = async ( yearnRegistry, } } + +export const getAuctionFactoryFromRegistry = async ( + auctionRegistryAddress: Address, + publicClient: PublicClient +) => { + const contract = getContract({ + address: auctionRegistryAddress, + abi: auctionRegistryABI, + client: publicClient, + }) + console.log('Fetching auction factory from auction registry...') + const auctionFactory = await contract.read.getLatestFactory().catch(() => { + console.warn('auctionFactory not found in auction registry') + return undefined + }) + console.log('Auction factory address fetched from registry.') + return auctionFactory +} + +export const getFeeRecipientFromAccountant = async ( + accountantAddress: Address, + publicClient: PublicClient +) => { + const contract = getContract({ + address: accountantAddress, + abi: accountantABI, + client: publicClient, + }) + console.log('Fetching fee recipient from accountant...') + const feeRecipient = await contract.read.feeRecipient().catch(() => { + console.warn('feeRecipient not found in accountant') + return undefined + }) + console.log('Fee recipient address fetched from accountant.') + return feeRecipient +} diff --git a/src/ethereum/v3Checks.ts b/src/ethereum/v3Checks.ts index 41c7a48e5..d4e8d81c0 100644 --- a/src/ethereum/v3Checks.ts +++ b/src/ethereum/v3Checks.ts @@ -3,6 +3,8 @@ import { getProtocolContractAddresses, readReleaseRegistryAll, readYearnRoleManager, + getAuctionFactoryFromRegistry, + getFeeRecipientFromAccountant, } from './v3Calls' import { Address, PublicClient, getAddress } from 'viem' import { V3ReleaseDataMap, V3ReleaseData } from './types' @@ -186,12 +188,27 @@ export const fetchAndCheckProtocolAddresses = async ( roleManagerFactory, failedChecks ) + + // Fetch auctionFactory from auctionRegistry + const auctionRegistryAddress = constants.protocolPeriphery.auctionRegistry as Address + const auctionFactoryFromRegistry = await getAuctionFactoryFromRegistry( + auctionRegistryAddress, + publicClient + ) + const auctionFactoryCheck = await validateAddress( + constants.protocolPeriphery.auctionFactory, + 'v3AuctionFactory', + auctionFactoryFromRegistry || '0x0000000000000000000000000000000000000000', + failedChecks + ) + if ( !aprOracleCheck || !aprOracleENSCheck || !routerCheck || !reportTriggerCheck || - !roleManagerFactoryCheck + !roleManagerFactoryCheck || + !auctionFactoryCheck ) { checkFlag = false } @@ -200,6 +217,7 @@ export const fetchAndCheckProtocolAddresses = async ( routerCheck, reportTriggerCheck, roleManagerFactoryCheck, + auctionFactoryCheck, } console.log('V3 protocol address validation complete. \n') return { @@ -357,13 +375,27 @@ export const fetchAndCheckYearnV3Addresses = async ( failedChecks ) + // Fetch feeRecipient from Accountant and validate against dumper + const accountantAddress = constants.yearnV3ContractsMainnet.accountant as Address + const feeRecipientFromAccountant = await getFeeRecipientFromAccountant( + accountantAddress, + publicClient + ) + const feeRecipientCheck = await validateAddress( + constants.yearnV3ContractsMainnet.dumper, + 'yearnV3FeeRecipient (Dumper)', + feeRecipientFromAccountant || '0x0000000000000000000000000000000000000000', + failedChecks + ) + if ( !accountantCheck || !accountantENSCheck || !registryCheck || !registryENSCheck || !debtAllocatorCheck || - !daddyCheck + !daddyCheck || + !feeRecipientCheck ) { checkFlag = false } @@ -373,6 +405,7 @@ export const fetchAndCheckYearnV3Addresses = async ( registryCheck, debtAllocatorCheck, daddyCheck, + feeRecipientCheck, } console.log('Yearn V3 Periphery address validation complete. \n') return { addresses, checks, checkFlag }