Skip to content

Commit

Permalink
feat: gnosis deployment (#209)
Browse files Browse the repository at this point in the history
* first draft immutable borrow contracts

* 2nd draft gold stablecoin

* first batch of test done

* update final hash of vaultManager implementation

* feat: gnosis deployment

* fix: failing tests

---------

Co-authored-by: gs8nrv <[email protected]>
  • Loading branch information
sogipec and GuillaumeNervoXS authored Apr 26, 2023
1 parent 0937abd commit df978a3
Show file tree
Hide file tree
Showing 28 changed files with 7,703 additions and 87 deletions.
12 changes: 2 additions & 10 deletions contracts/agToken/AgTokenSideChainImmutable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,10 @@ import "./AgTokenSideChain.sol";
/// @author Angle Labs, Inc.
/// @notice Contract for immutable Angle's stablecoins
contract AgTokenSideChainImmutable is AgTokenSideChain {
constructor(
string memory name_,
string memory symbol_,
address _treasury
) AgTokenSideChain() initializer {
constructor(string memory name_, string memory symbol_, address _treasury) AgTokenSideChain() initializer {
_initializeBase(name_, symbol_, _treasury);
}

/// @inheritdoc BaseAgTokenSideChain
function _initialize(
string memory name_,
string memory symbol_,
address _treasury
) internal override {}
function _initialize(string memory name_, string memory symbol_, address _treasury) internal override {}
}
24 changes: 4 additions & 20 deletions contracts/agToken/BaseAgTokenSideChain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,7 @@ contract BaseAgTokenSideChain is IAgToken, ERC20PermitUpgradeable {

/// @notice Wraps `_initializeBase` for `BaseAgTokenSideChain` and makes a safety check
/// on `_treasury`
function _initialize(
string memory name_,
string memory symbol_,
address _treasury
) internal virtual initializer {
function _initialize(string memory name_, string memory symbol_, address _treasury) internal virtual initializer {
if (address(ITreasury(_treasury).stablecoin()) != address(this)) revert InvalidTreasury();
_initializeBase(name_, symbol_, _treasury);
}
Expand All @@ -84,11 +80,7 @@ contract BaseAgTokenSideChain is IAgToken, ERC20PermitUpgradeable {
/// @param name_ Name of the token
/// @param symbol_ Symbol of the token
/// @param _treasury Reference to the `Treasury` contract associated to this agToken implementation
function _initializeBase(
string memory name_,
string memory symbol_,
address _treasury
) internal virtual {
function _initializeBase(string memory name_, string memory symbol_, address _treasury) internal virtual {
__ERC20Permit_init(name_);
__ERC20_init(name_, symbol_);
treasury = _treasury;
Expand Down Expand Up @@ -127,11 +119,7 @@ contract BaseAgTokenSideChain is IAgToken, ERC20PermitUpgradeable {
}

/// @inheritdoc IAgToken
function burnFrom(
uint256 amount,
address burner,
address sender
) external onlyMinter {
function burnFrom(uint256 amount, address burner, address sender) external onlyMinter {
_burnFromNoRedeem(amount, burner, sender);
}

Expand Down Expand Up @@ -166,11 +154,7 @@ contract BaseAgTokenSideChain is IAgToken, ERC20PermitUpgradeable {
/// @notice Internal version of the function `burnFromNoRedeem`
/// @param amount Amount to burn
/// @dev It is at the level of this function that allowance checks are performed
function _burnFromNoRedeem(
uint256 amount,
address burner,
address sender
) internal {
function _burnFromNoRedeem(uint256 amount, address burner, address sender) internal {
if (burner != sender) {
uint256 currentAllowance = allowance(burner, sender);
if (currentAllowance < amount) revert BurnAmountExceedsAllowance();
Expand Down
21 changes: 8 additions & 13 deletions contracts/treasury/Treasury.sol
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,9 @@ contract Treasury is ITreasury, Initializable {
/// @return badDebtValue Value the `badDebt` should have after the call if it was updated
/// @dev This internal function is never to be called alone, and should always be called in conjunction
/// with the `_updateSurplusAndBadDebt` function
function _fetchSurplusFromList(address[] memory vaultManagers)
internal
returns (uint256 surplusBufferValue, uint256 badDebtValue)
{
function _fetchSurplusFromList(
address[] memory vaultManagers
) internal returns (uint256 surplusBufferValue, uint256 badDebtValue) {
badDebtValue = badDebt;
surplusBufferValue = surplusBuffer;
uint256 newSurplus;
Expand All @@ -246,10 +245,10 @@ contract Treasury is ITreasury, Initializable {
/// @dev When calling this function, it is possible that there is a positive `surplusBufferValue` and `badDebtValue`,
/// this function tries to reconcile both values and makes sure that we either have surplus or bad debt but not both
/// at the same time
function _updateSurplusAndBadDebt(uint256 surplusBufferValue, uint256 badDebtValue)
internal
returns (uint256, uint256)
{
function _updateSurplusAndBadDebt(
uint256 surplusBufferValue,
uint256 badDebtValue
) internal returns (uint256, uint256) {
if (badDebtValue != 0) {
// If we have bad debt we need to burn stablecoins that accrued to the protocol
// We still need to make sure that we're not burning too much or as much as we can if the debt is big
Expand Down Expand Up @@ -336,11 +335,7 @@ contract Treasury is ITreasury, Initializable {
/// and from the flash loan module
/// @dev If the token to recover is the stablecoin, tokens recovered are fetched
/// from the surplus and not from the `surplusBuffer`
function recoverERC20(
address tokenAddress,
address to,
uint256 amountToRecover
) external onlyGovernor {
function recoverERC20(address tokenAddress, address to, uint256 amountToRecover) external onlyGovernor {
// Cannot recover stablecoin if badDebt or tap into the surplus buffer
if (tokenAddress == address(stablecoin)) {
_fetchSurplusFromAll();
Expand Down
1 change: 1 addition & 0 deletions contracts/treasury/TreasuryImmutable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ contract TreasuryImmutable is Treasury {

// =============================== Errors ======================================

error AlreadySetStablecoin();
error InvalidVaultManager();
error InvalidStablecoin();

Expand Down
39 changes: 11 additions & 28 deletions contracts/vaultManager/VaultManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions {
if (_oracle.treasury() != _treasury) revert InvalidTreasury();
treasury = _treasury;
collateral = _collateral;
_collatBase = 10**(IERC20Metadata(address(collateral)).decimals());
_collatBase = 10 ** (IERC20Metadata(address(collateral)).decimals());
stablecoin = IAgToken(_treasury.stablecoin());
oracle = _oracle;
string memory _name = string.concat("Angle Protocol ", _symbol, " Vault");
Expand Down Expand Up @@ -343,7 +343,7 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions {

uint256 stablecoinAmountLessFeePaid = (stablecoinAmount *
(BASE_PARAMS - repayFee_) *
(BASE_PARAMS - _borrowFee)) / (BASE_PARAMS**2);
(BASE_PARAMS - _borrowFee)) / (BASE_PARAMS ** 2);
surplus += stablecoinAmount - stablecoinAmountLessFeePaid;
_repayDebt(vaultID, stablecoinAmountLessFeePaid, 0);
}
Expand All @@ -365,11 +365,10 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions {
/// @param liquidator Address of the liquidator which will be performing the liquidation
/// @return liqOpp Description of the opportunity of liquidation
/// @dev This function will revert if it's called on a vault that does not exist
function checkLiquidation(uint256 vaultID, address liquidator)
external
view
returns (LiquidationOpportunity memory liqOpp)
{
function checkLiquidation(
uint256 vaultID,
address liquidator
) external view returns (LiquidationOpportunity memory liqOpp) {
liqOpp = _checkLiquidation(
vaultData[vaultID],
liquidator,
Expand All @@ -392,15 +391,7 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions {
Vault memory vault,
uint256 oracleValue,
uint256 newInterestAccumulator
)
internal
view
returns (
uint256 healthFactor,
uint256 currentDebt,
uint256 collateralAmountInStable
)
{
) internal view returns (uint256 healthFactor, uint256 currentDebt, uint256 collateralAmountInStable) {
currentDebt = (vault.normalizedDebt * newInterestAccumulator) / BASE_INTEREST;
collateralAmountInStable = (vault.collateralAmount * oracleValue) / _collatBase;
if (currentDebt == 0) healthFactor = type(uint256).max;
Expand Down Expand Up @@ -803,7 +794,7 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions {
// Checking if we're in a situation where the health factor is an increasing or a decreasing function of the
// amount repaid. In the first case, the health factor is an increasing function which means that the liquidator
// can bring the vault to the target health ratio
if (healthFactor * liquidationDiscount * surcharge >= collateralFactor * BASE_PARAMS**2) {
if (healthFactor * liquidationDiscount * surcharge >= collateralFactor * BASE_PARAMS ** 2) {
// This is the max amount to repay that will bring the person to the target health factor
// Denom is always positive when a vault gets liquidated in this case and when the health factor
// is an increasing function of the amount of stablecoins repaid
Expand All @@ -812,7 +803,7 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions {
((targetHealthFactor * currentDebt - collateralAmountInStable * collateralFactor) *
BASE_PARAMS *
liquidationDiscount) /
(surcharge * targetHealthFactor * liquidationDiscount - (BASE_PARAMS**2) * collateralFactor);
(surcharge * targetHealthFactor * liquidationDiscount - (BASE_PARAMS ** 2) * collateralFactor);
// Need to check for the dust as liquidating should not leave a dusty amount in the vault
uint256 dustParameter = dustLiquidation;
if (currentDebt * BASE_PARAMS <= maxAmountToRepay * surcharge + dustParameter * BASE_PARAMS) {
Expand Down Expand Up @@ -950,11 +941,7 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions {
/// @param _dustLiquidation New `dustLiquidation` value
/// @param dustCollateral_ New minimum collateral allowed in a vault after a liquidation
/// @dev dustCollateral_ is in stable value
function setDusts(
uint256 _dust,
uint256 _dustLiquidation,
uint256 dustCollateral_
) external onlyGovernor {
function setDusts(uint256 _dust, uint256 _dustLiquidation, uint256 dustCollateral_) external onlyGovernor {
if (_dust > _dustLiquidation) revert InvalidParameterValue();
dust = _dust;
dustLiquidation = _dustLiquidation;
Expand Down Expand Up @@ -982,11 +969,7 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions {
/// @param amount Collateral amount balance of the owner of vaultID increase/decrease
/// @param add Whether the balance should be increased/decreased
/// @param vaultID Vault which sees its collateral amount changed
function _checkpointCollateral(
uint256 vaultID,
uint256 amount,
bool add
) internal virtual {}
function _checkpointCollateral(uint256 vaultID, uint256 amount, bool add) internal virtual {}

/// @notice Get `paused` in storage only if needed
function _paused() internal view virtual returns (bool) {
Expand Down
17 changes: 11 additions & 6 deletions deploy/0_proxyAdmin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,33 @@ const func: DeployFunction = async ({ deployments, ethers, network }) => {
const { deployer } = await ethers.getNamedSigners();
let proxyAdmin: ProxyAdmin;
let guardian: string;
let governor: string;

if (!network.live) {
// If we're in mainnet fork, we're using the `ProxyAdmin` address from mainnet
guardian = CONTRACTS_ADDRESSES[ChainId.MAINNET]?.Guardian!;
governor = CONTRACTS_ADDRESSES[ChainId.MAINNET]?.Governor!;
} else {
// Otherwise, we're using the proxy admin address from the desired network
guardian = CONTRACTS_ADDRESSES[network.config.chainId as ChainId]?.Guardian!;
guardian = '0xf0A31faec2B4fC6396c65B1aF1F6A71E653f11F0';
governor = '0x0F70EeD1Bb51d5eDB1a2E46142638df959bAFD69';
}

/*
console.log(`Now deploying ProxyAdmin on the chain ${network.config.chainId}`);
console.log('Guardian address is ', guardian);
await deploy('ProxyAdminGuardian', {
console.log('Governor address is ', governor);
await deploy('ProxyAdmin', {
contract: 'ProxyAdmin',
from: deployer.address,
log: !argv.ci,
});
const proxyAdminAddress = (await ethers.getContract('ProxyAdminGuardian')).address;
*/
const proxyAdminAddress = (await ethers.getContract('ProxyAdmin')).address;

proxyAdmin = new ethers.Contract(proxyAdminAddress, ProxyAdmin__factory.createInterface(), deployer) as ProxyAdmin;

console.log(`Transferring ownership of the proxy admin to the guardian ${guardian}`);
await (await proxyAdmin.connect(deployer).transferOwnership(guardian)).wait();
console.log(`Transferring ownership of the proxy admin to the governor ${governor}`);
await (await proxyAdmin.connect(deployer).transferOwnership(governor)).wait();
console.log('Success');
};

Expand Down
3 changes: 2 additions & 1 deletion deploy/2_agTokenImplementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const argv = yargs.env('').boolean('ci').parseSync();
const func: DeployFunction = async ({ deployments, ethers, network }) => {
const { deploy } = deployments;
const { deployer } = await ethers.getNamedSigners();
const stableName = 'GOLD';
const stableName = 'EUR';

let implementationName: string;
let proxyAdmin: string;
Expand All @@ -18,6 +18,7 @@ const func: DeployFunction = async ({ deployments, ethers, network }) => {
} else {
implementationName = 'AgTokenSideChainMultiBridge';
proxyAdmin = registry(network.config.chainId as ChainId)?.ProxyAdmin!;
proxyAdmin = '0x9a5b060Bd7b8f86c4C0D720a17367729670AfB19';
}

console.log(`Now deploying the implementation for AgToken on ${network.name}`);
Expand Down
6 changes: 4 additions & 2 deletions deploy/3_treasury.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const func: DeployFunction = async ({ deployments, ethers, network }) => {
const { deployer } = await ethers.getNamedSigners();
let proxyAdmin: string;
let coreBorrow: string;
const stableName = 'GOLD';
const stableName = 'EUR';
const agTokenName = `ag${stableName}`;

const agTokenAddress = (await deployments.get(`AgToken_${stableName}`)).address;
Expand All @@ -24,6 +24,8 @@ const func: DeployFunction = async ({ deployments, ethers, network }) => {
} else {
proxyAdmin = registry(network.config.chainId as ChainId)?.ProxyAdmin!;
coreBorrow = registry(network.config.chainId as ChainId)?.CoreBorrow!;
proxyAdmin = '0x9a5b060Bd7b8f86c4C0D720a17367729670AfB19';
coreBorrow = '0x3E399AE5B4D8bc0021e53b51c8BCdD66DD62c03b';
}

let treasuryImplementation: string;
Expand Down Expand Up @@ -61,5 +63,5 @@ const func: DeployFunction = async ({ deployments, ethers, network }) => {
};

func.tags = ['treasury'];
func.dependencies = ['agTokenImplementation'];
// func.dependencies = ['agTokenImplementation'];
export default func;
4 changes: 2 additions & 2 deletions deploy/bridges/LayerZeroBridgeToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { deployImplem, deployProxy } from '../helpers';
const stable = 'EUR';

const func: DeployFunction = async ({ ethers, network }) => {
const treasury = await ethers.getContract('Treasury');
const treasury = await ethers.getContract('Treasury_EUR');
const proxyAdmin = await ethers.getContract('ProxyAdmin');

const endpointAddr = (LZ_ENDPOINTS as { [name: string]: string })[network.name];
Expand All @@ -24,7 +24,7 @@ const func: DeployFunction = async ({ ethers, network }) => {
`LZ-ag${stable}`,
endpointAddr,
treasury.address,
parseEther('100000'),
parseEther('0'),
]),
);

Expand Down
1 change: 1 addition & 0 deletions deploy/bridges/LayerZeroSetSources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const func: DeployFunction = async ({ ethers, network }) => {
avalanche: '0x14C00080F97B9069ae3B4Eb506ee8a633f8F5434',
bsc: '0xe9f183FC656656f1F17af1F2b0dF79b8fF9ad8eD',
celo: '0xf1dDcACA7D17f8030Ab2eb54f2D9811365EFe123',
gnosis: '0xFA5Ed56A203466CbBC2430a43c66b9D8723528E7',
};

const local = OFTs[network.name];
Expand Down
2 changes: 2 additions & 0 deletions deploy/constants/layerzeroChainIds.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"optimism": 111,
"fantom": 112,
"celo": 125,
"gnosis": 145,
"zksync": 165,
"rinkeby": 10001,
"bsc-testnet": 10002,
"fuji": 10006,
Expand Down
2 changes: 2 additions & 0 deletions deploy/constants/layerzeroEndpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"optimism": "0x3c2269811836af69497E5F486A85D7316753cf62",
"fantom": "0xb6319cC6c8c27A8F5dAF0dD3DF91EA35C4720dd7",
"celo": "0x3A73033C0b1407574C76BdBAc67f126f6b4a9AA9",
"gnosis": "0x9740FF91F1985D8d2B71494aE1A2f723bb3Ed9E4",
"zksync": "0x9b896c0e23220469C7AE69cb4BbAE391eAa4C8da",
"rinkeby": "0x79a63d6d8BBD5c6dfc774dA79bCcD948EAcb53FA",
"bsc-testnet": "0x6Fcb97553D41516Cb228ac03FdC8B9a0a9df04A1",
"fuji": "0x93f54D755A063cE7bB9e6Ac47Eccc8e33411d706",
Expand Down
5 changes: 5 additions & 0 deletions deploy/networks/gnosis.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"angleLabs": "0xf4b426A9849933c83041D6554cb39955ddA5c767",
"governor": "0x0F70EeD1Bb51d5eDB1a2E46142638df959bAFD69",
"guardian": "0xf0A31faec2B4fC6396c65B1aF1F6A71E653f11F0"
}
1 change: 1 addition & 0 deletions deployments/gnosis/.chainId
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
100
Loading

0 comments on commit df978a3

Please sign in to comment.