Skip to content

Commit

Permalink
Merge pull request #4 from yearn/using_shares
Browse files Browse the repository at this point in the history
feat: transfer shares
  • Loading branch information
Schlagonia authored Apr 24, 2024
2 parents afff1f9 + 77d7fa4 commit 767b946
Show file tree
Hide file tree
Showing 15 changed files with 837 additions and 556 deletions.
12 changes: 0 additions & 12 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,3 @@ jobs:

- name: run linter check on *.sol file
run: yarn lint

commits:
runs-on: ubuntu-latest

steps:
- name: Check out github repository
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Run commitlint
uses: wagoid/commitlint-github-action@v5
59 changes: 24 additions & 35 deletions src/DeployerBase.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;

Check warning on line 2 in src/DeployerBase.sol

View workflow job for this annotation

GitHub Actions / solidity

Compiler version ^0.8.20 does not satisfy the 0.8.18 semver requirement

import {Positions} from "./Positions.sol";
import {Proxy} from "@zkevm-stb/Proxy.sol";
import {ICREATE3Factory} from "./interfaces/ICREATE3Factory.sol";
import {IPolygonZkEVMBridge} from "./interfaces/Polygon/IPolygonZkEVMBridge.sol";
Expand All @@ -9,49 +10,37 @@ import {IPolygonZkEVMBridge} from "./interfaces/Polygon/IPolygonZkEVMBridge.sol"
* @title DeployerBase
* @notice To be inherited by the L1 and L2 Deployer's for common functionality.
*/
abstract contract DeployerBase {
contract DeployerBase is Positions {
uint32 internal constant ORIGIN_NETWORK_ID = 0;

/// @notice Address of the ICREATE3Factory contract used for deployment
ICREATE3Factory internal constant create3Factory =

Check warning on line 17 in src/DeployerBase.sol

View workflow job for this annotation

GitHub Actions / solidity

Constant name must be in capitalized SNAKE_CASE
ICREATE3Factory(0x93FEC2C00BfE902F733B57c5a6CeeD7CD1384AE1);

/*//////////////////////////////////////////////////////////////
POSITION ID'S
//////////////////////////////////////////////////////////////*/

bytes32 public constant ESCROW_IMPLEMENTATION =
keccak256("Escrow Implementation");
bytes32 public constant L1_DEPLOYER = keccak256("L1 Deployer");
bytes32 public constant L2_DEPLOYER = keccak256("L2 Deployer");

/// @notice Address of the ICREATE3Factory contract used for deployment
ICREATE3Factory internal constant create3Factory =
ICREATE3Factory(0x93FEC2C00BfE902F733B57c5a6CeeD7CD1384AE1);

/// @notice Immutable original chain ID
uint256 public immutable originalChainID;
bytes32 public constant ESCROW_IMPLEMENTATION =
keccak256("Escrow Implementation");

/// @notice Address of the PolygonZkEVMBridge contract
IPolygonZkEVMBridge public immutable polygonZkEVMBridge;

Check warning on line 30 in src/DeployerBase.sol

View workflow job for this annotation

GitHub Actions / solidity

Immutable variables name are set to be in capitalized SNAKE_CASE

constructor(address _polygonZkEVMBridge) {
constructor(
address _polygonZkEVMBridge,
address _l1Deployer,
address _l2Deployer,
address _escrowImplementation
) {
polygonZkEVMBridge = IPolygonZkEVMBridge(_polygonZkEVMBridge);
originalChainID = block.chainid;
_setPositionHolder(L1_DEPLOYER, _l1Deployer);
_setPositionHolder(L2_DEPLOYER, _l2Deployer);
_setPositionHolder(ESCROW_IMPLEMENTATION, _escrowImplementation);
}

/**
* @notice Abstract functions to get the Layer 1 deployer address
* @return Address of the Layer 1 deployer
*/
function getL1Deployer() public view virtual returns (address);

/**
* @notice Abstract functions to get the Layer 2 deployer address
* @return Address of the Layer 2 deployer
*/
function getL2Deployer() public view virtual returns (address);

/**
* @notice Abstract functions to get the Escrow Implementation address
* @return Address of the Escrow Implementation.
*/
function getEscrowImplementation() external view virtual returns (address);

/**
* @notice Get expected L2 token address for a given asset
* @param _l1TokenAddress Address of the L1 token
Expand All @@ -62,7 +51,7 @@ abstract contract DeployerBase {
) public view virtual returns (address) {
return
create3Factory.getDeployed(
getL2Deployer(),
getPositionHolder(L2_DEPLOYER),
keccak256(abi.encodePacked(bytes("L2Token:"), _l1TokenAddress))
);
}
Expand All @@ -77,7 +66,7 @@ abstract contract DeployerBase {
) public view virtual returns (address) {
return
create3Factory.getDeployed(
getL1Deployer(),
getPositionHolder(L1_DEPLOYER),
keccak256(abi.encodePacked(bytes("L1Escrow:"), _l1TokenAddress))
);
}
Expand All @@ -92,7 +81,7 @@ abstract contract DeployerBase {
) public view virtual returns (address) {
return
create3Factory.getDeployed(
getL2Deployer(),
getPositionHolder(L2_DEPLOYER),
keccak256(abi.encodePacked(bytes("L2Escrow:"), _l1TokenAddress))
);
}
Expand All @@ -102,12 +91,12 @@ abstract contract DeployerBase {
* @param _l1TokenAddress Address of the L1 token
* @return Address of the expected L2 converter contract
*/
function getL2ConvertorAddress(
function getL2ConverterAddress(
address _l1TokenAddress
) public view virtual returns (address) {
return
create3Factory.getDeployed(
getL2Deployer(),
getPositionHolder(L2_DEPLOYER),
keccak256(
abi.encodePacked(
bytes("L2TokenConverter:"),
Expand Down
47 changes: 11 additions & 36 deletions src/L1Deployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,12 @@ pragma solidity ^0.8.20;

import {Proxy} from "@zkevm-stb/Proxy.sol";

Check warning on line 4 in src/L1Deployer.sol

View workflow job for this annotation

GitHub Actions / solidity

imported name Proxy is not used
import {RoleManager} from "./RoleManager.sol";
import {DeployerBase} from "./DeployerBase.sol";
import {L1YearnEscrow} from "./L1YearnEscrow.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IPolygonRollupManager, IPolygonRollupContract} from "./interfaces/Polygon/IPolygonRollupManager.sol";

// TODO:
// getters for custom position holders
// create 3 factory
// External create3 Address getters
//
/// Governance Structure:
// 1. GOVERNATOR Can change the Holders, Impl and addresses (Rare) 2/3 meta multisig (No Roles)
// 2. CZAR/DADDY Sets strategies All Roles
// 3. Management/SMS Day to Day Ops

/// @title PolyYearn Stake the Bridge Role Manager.
contract L1Deployer is DeployerBase, RoleManager {
/// @title Polygon CDK Stake the Bridge L1 Deployer.
contract L1Deployer is RoleManager {
event RegisteredNewRollup(
uint32 indexed rollupID,
address indexed rollupContract,
Expand Down Expand Up @@ -72,23 +61,25 @@ contract L1Deployer is DeployerBase, RoleManager {
address _registry,
address _allocatorFactory,
address _polygonZkEVMBridge,
address _l2Deployer,
address _escrowImplementation
)
DeployerBase(_polygonZkEVMBridge)
RoleManager(
_governator,
_czar,
_management,
_emergencyAdmin,
_keeper,
_registry,
_allocatorFactory
_allocatorFactory,
_polygonZkEVMBridge,
_l2Deployer,
_escrowImplementation
)
{
rollupManager = IPolygonRollupManager(
polygonZkEVMBridge.polygonRollupManager()
);
_positions[ESCROW_IMPLEMENTATION].holder = _escrowImplementation;
}

function registerRollup(
Expand Down Expand Up @@ -151,7 +142,7 @@ contract L1Deployer is DeployerBase, RoleManager {

// If not, deploy one and do full setup
if (_vault == address(0)) {
_vault = _newVault(DEFAULT_ID, _asset);
_vault = _newVault(ORIGIN_NETWORK_ID, _asset);
}

// Deploy L1 Escrow.
Expand All @@ -171,7 +162,9 @@ contract L1Deployer is DeployerBase, RoleManager {
address _asset,
address _vault
) external virtual onlyRollupAdmin(_rollupID) {
_addNewVault(_rollupID, _vault);
if (!isVaultsRoleManager(_vault)) {
_addNewVault(_rollupID, _vault);
}
_newCustomVault(_rollupID, _asset, _vault);
}

Expand Down Expand Up @@ -258,22 +251,4 @@ contract L1Deployer is DeployerBase, RoleManager {
) public view virtual returns (address) {
return chainConfig[_rollupID].escrows[_asset];
}

function getL1Deployer() public view virtual override returns (address) {
return address(this);
}

function getL2Deployer() public view virtual override returns (address) {
return getPositionHolder(L2_DEPLOYER);
}

function getEscrowImplementation()
external
view
virtual
override
returns (address)
{
return getPositionHolder(ESCROW_IMPLEMENTATION);
}
}
79 changes: 50 additions & 29 deletions src/L1YearnEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ contract L1YearnEscrow is L1Escrow {
}
}

function vaultAddress() public view returns (IVault) {
function vaultAddress() public view returns (address) {
VaultStorage storage $ = _getVaultStorage();
return $.vaultAddress;
return address($.vaultAddress);
}

function minimumBuffer() public view returns (uint256) {
Expand Down Expand Up @@ -114,17 +114,21 @@ contract L1YearnEscrow is L1Escrow {
function _receiveTokens(
uint256 amount
) internal virtual override whenNotPaused {
super._receiveTokens(amount);
originTokenAddress().safeTransferFrom(
msg.sender,
address(this),
amount
);

VaultStorage storage $ = _getVaultStorage();
uint256 _minimumBuffer = $.minimumBuffer;
// Deposit to the vault if above buffer
if (_minimumBuffer != 0) {
uint256 underlyingBalance = originTokenAddress().balanceOf(
address(this)
);
if (underlyingBalance <= _minimumBuffer) {
return;
}

if (underlyingBalance <= _minimumBuffer) return;

unchecked {
amount = underlyingBalance - _minimumBuffer;
Expand All @@ -135,37 +139,50 @@ contract L1YearnEscrow is L1Escrow {
}

/**
* @dev Handle the transfer of the tokens
* @dev Handle the transfer of the tokens. Will send shares instead of
* the underlying asset if the vault is illiquid.
* @param destinationAddress Address destination that will receive the tokens on the other network
* @param amount Token amount
*/
function _transferTokens(
address destinationAddress,
uint256 amount
) internal virtual override whenNotPaused {
VaultStorage storage $ = _getVaultStorage();

// Check if there is enough loose balance.
uint256 underlyingBalance = originTokenAddress().balanceOf(
address(this)
);
if (underlyingBalance != 0) {
if (underlyingBalance >= amount) {
super._transferTokens(destinationAddress, amount);
return;
}
IERC20 originToken = originTokenAddress();

// Check if there is enough buffer.
uint256 underlyingBalance = originToken.balanceOf(address(this));
if (underlyingBalance >= amount) {
// Only use buffer if it covers the full amount.
originToken.safeTransfer(destinationAddress, amount);
return;
}

uint256 maxWithdraw = $.vaultAddress.maxWithdraw(address(this));
if (maxWithdraw < amount) {
super._transferTokens(destinationAddress, underlyingBalance);
// Check if the vault will allow for a full withdraw.
IVault _vault = _getVaultStorage().vaultAddress;
uint256 maxWithdraw = _vault.maxWithdraw(address(this));
// If liquidity will not allow for a full withdraw.
if (amount > maxWithdraw) {
// First use any loose balance.
if (underlyingBalance != 0) {
originToken.safeTransfer(destinationAddress, underlyingBalance);
unchecked {
amount = amount - underlyingBalance;
}
}

// Check again to account for if there was underlying
if (amount > maxWithdraw) {
// Send an equivalent amount of shares for the difference.
uint256 shares = _vault.convertToShares(amount - maxWithdraw);
_vault.transfer(destinationAddress, shares);
if (maxWithdraw == 0) return;
amount = maxWithdraw;
}
}

// Withdraw from vault to receiver.
$.vaultAddress.withdraw(amount, destinationAddress, address(this));
_vault.withdraw(amount, destinationAddress, address(this));
}

// ****************************
Expand All @@ -175,15 +192,17 @@ contract L1YearnEscrow is L1Escrow {
/**
* @dev Escrow manager can withdraw the token backing
* @param _recipient the recipient address
* @param _amount The amount of token
* @param _amount The amount of token in underlying
*/
function withdraw(
address _recipient,
uint256 _amount
) external virtual override onlyRole(ESCROW_MANAGER_ROLE) whenNotPaused {
VaultStorage storage $ = _getVaultStorage();
uint256 shares = $.vaultAddress.convertToShares(_amount);
$.vaultAddress.transfer(_recipient, shares);
IVault _vault = _getVaultStorage().vaultAddress;
// Transfer the equivalent amount of vault shares
uint256 shares = _vault.convertToShares(_amount);
_vault.transfer(_recipient, shares);

emit Withdraw(_recipient, _amount);
}

Expand All @@ -201,10 +220,12 @@ contract L1YearnEscrow is L1Escrow {
) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
VaultStorage storage $ = _getVaultStorage();
IVault oldVault = $.vaultAddress;
IERC20 originToken = originTokenAddress();

// If re-initializing to a new vault address.
if (address(oldVault) != address(0)) {
// Lower allowance to 0
originTokenAddress().forceApprove(address(oldVault), 0);
originToken.forceApprove(address(oldVault), 0);

uint256 balance = oldVault.balanceOf(address(this));
// Withdraw the full balance of the current vault.
Expand All @@ -216,10 +237,10 @@ contract L1YearnEscrow is L1Escrow {
// Migrate to new vault if applicable
if (_vaultAddress != address(0)) {
// Max approve the new vault
originTokenAddress().forceApprove(_vaultAddress, 2 ** 256 - 1);
originToken.forceApprove(_vaultAddress, 2 ** 256 - 1);

// Deposit any loose funds
uint256 balance = originTokenAddress().balanceOf(address(this));
uint256 balance = originToken.balanceOf(address(this));
if (balance != 0)
IVault(_vaultAddress).deposit(balance, address(this));
}
Expand Down
Loading

0 comments on commit 767b946

Please sign in to comment.