From 523b2be2bc59a9090af5f29775b1591e4189d9a9 Mon Sep 17 00:00:00 2001 From: Jeroen Offerijns Date: Wed, 23 Aug 2023 15:54:01 +0200 Subject: [PATCH] Format --- lib/forge-std | 2 +- src/Escrow.sol | 2 +- src/Gateway.sol | 80 +++--- src/InvestmentManager.sol | 385 ++++++++++++++++++--------- src/Messages.sol | 46 ++-- src/admin/PauseAdmin.sol | 1 - src/auth/auth.sol | 9 +- src/liquidityPool/Factory.sol | 36 ++- src/liquidityPool/LiquidityPool.sol | 40 ++- src/routers/axelar/EVMRouter.sol | 9 +- src/token/erc20.sol | 2 +- src/token/memberlist.sol | 2 + src/token/restricted.sol | 2 +- test/Admin.t.sol | 1 - test/InvestmentManager.t.sol | 189 +++++++------ test/LiquidityPool.t.sol | 349 ++++++++++++------------ test/Messages.t.sol | 71 +++-- test/mock/MockHomeLiquidityPools.sol | 12 +- 18 files changed, 694 insertions(+), 544 deletions(-) diff --git a/lib/forge-std b/lib/forge-std index cffb5628..4a650f2b 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit cffb5628775fbf120bfc3c123149f6a6d99dc275 +Subproject commit 4a650f2bed222c4452383489e4d8cdbaf3d19fc5 diff --git a/src/Escrow.sol b/src/Escrow.sol index f2b6b319..a8ccf642 100644 --- a/src/Escrow.sol +++ b/src/Escrow.sol @@ -2,6 +2,7 @@ // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico // Copyright (C) 2021 Dai Foundation pragma solidity ^0.8.18; + import "./auth/auth.sol"; interface ApproveLike { @@ -9,7 +10,6 @@ interface ApproveLike { } contract Escrow is Auth { - event Approve(address indexed token, address indexed spender, uint256 value); constructor() { diff --git a/src/Gateway.sol b/src/Gateway.sol index 4f676cbe..62ee4493 100644 --- a/src/Gateway.sol +++ b/src/Gateway.sol @@ -20,8 +20,13 @@ interface InvestmentManagerLike { function updateMember(uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) external; function updateTokenPrice(uint64 poolId, bytes16 trancheId, uint128 price) external; function handleTransfer(uint128 currency, address recipient, uint128 amount) external; - function handleTransferTrancheTokens(uint64 poolId, bytes16 trancheId, uint128 currency, address destinationAddress, uint128 amount) - external; + function handleTransferTrancheTokens( + uint64 poolId, + bytes16 trancheId, + uint128 currency, + address destinationAddress, + uint128 amount + ) external; function handleExecutedDecreaseInvestOrder( uint64 poolId, bytes16 trancheId, @@ -99,11 +104,11 @@ contract Gateway { ) { investmentManager = InvestmentManagerLike(investmentManager_); router = RouterLike(router_); - + shortScheduleWait = shortScheduleWait_; longScheduleWait = longScheduleWait_; gracePeriod = gracePeriod_; - + wards[msg.sender] = 1; emit Rely(msg.sender); } @@ -183,7 +188,7 @@ contract Gateway { bytes16 trancheId, address sender, bytes32 destinationAddress, - uint128 currencyId, + uint128 currencyId, uint128 amount ) public onlyInvestmentManager pauseable { router.send( @@ -221,7 +226,11 @@ contract Gateway { ); } - function transfer(uint128 token, address sender, bytes32 receiver, uint128 amount) public onlyInvestmentManager pauseable { + function transfer(uint128 token, address sender, bytes32 receiver, uint128 amount) + public + onlyInvestmentManager + pauseable + { router.send(Messages.formatTransfer(token, addressToBytes32(sender), receiver, amount)); } @@ -230,9 +239,7 @@ contract Gateway { onlyInvestmentManager pauseable { - router.send( - Messages.formatIncreaseInvestOrder(poolId, trancheId, addressToBytes32(investor), currency, amount) - ); + router.send(Messages.formatIncreaseInvestOrder(poolId, trancheId, addressToBytes32(investor), currency, amount)); } function decreaseInvestOrder(uint64 poolId, bytes16 trancheId, address investor, uint128 currency, uint128 amount) @@ -240,9 +247,7 @@ contract Gateway { onlyInvestmentManager pauseable { - router.send( - Messages.formatDecreaseInvestOrder(poolId, trancheId, addressToBytes32(investor), currency, amount) - ); + router.send(Messages.formatDecreaseInvestOrder(poolId, trancheId, addressToBytes32(investor), currency, amount)); } function increaseRedeemOrder(uint64 poolId, bytes16 trancheId, address investor, uint128 currency, uint128 amount) @@ -250,9 +255,7 @@ contract Gateway { onlyInvestmentManager pauseable { - router.send( - Messages.formatIncreaseRedeemOrder(poolId, trancheId, addressToBytes32(investor), currency, amount) - ); + router.send(Messages.formatIncreaseRedeemOrder(poolId, trancheId, addressToBytes32(investor), currency, amount)); } function decreaseRedeemOrder(uint64 poolId, bytes16 trancheId, address investor, uint128 currency, uint128 amount) @@ -260,16 +263,22 @@ contract Gateway { onlyInvestmentManager pauseable { - router.send( - Messages.formatDecreaseRedeemOrder(poolId, trancheId, addressToBytes32(investor), currency, amount) - ); + router.send(Messages.formatDecreaseRedeemOrder(poolId, trancheId, addressToBytes32(investor), currency, amount)); } - function collectInvest(uint64 poolId, bytes16 trancheId, address investor, uint128 currency) public onlyInvestmentManager pauseable { + function collectInvest(uint64 poolId, bytes16 trancheId, address investor, uint128 currency) + public + onlyInvestmentManager + pauseable + { router.send(Messages.formatCollectInvest(poolId, trancheId, addressToBytes32(investor), currency)); } - function collectRedeem(uint64 poolId, bytes16 trancheId, address investor, uint128 currency) public onlyInvestmentManager pauseable { + function collectRedeem(uint64 poolId, bytes16 trancheId, address investor, uint128 currency) + public + onlyInvestmentManager + pauseable + { router.send(Messages.formatCollectRedeem(poolId, trancheId, addressToBytes32(investor), currency)); } @@ -297,8 +306,7 @@ contract Gateway { ) = Messages.parseAddTranche(_msg); investmentManager.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); } else if (Messages.isUpdateMember(_msg)) { - (uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) = - Messages.parseUpdateMember(_msg); + (uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) = Messages.parseUpdateMember(_msg); investmentManager.updateMember(poolId, trancheId, user, validUntil); } else if (Messages.isUpdateTrancheTokenPrice(_msg)) { (uint64 poolId, bytes16 trancheId, uint128 price) = Messages.parseUpdateTrancheTokenPrice(_msg); @@ -306,31 +314,19 @@ contract Gateway { } else if (Messages.isTransfer(_msg)) { (uint128 currency, address recipient, uint128 amount) = Messages.parseIncomingTransfer(_msg); investmentManager.handleTransfer(currency, recipient, amount); - } + } // else if (Messages.isTransferTrancheTokens(_msg)) { // (uint64 poolId, bytes16 trancheId, uint128 currencyId, address destinationAddress, uint128 amount) = // Messages.parseTransferTrancheTokens20(_msg); // investmentManager.handleTransferTrancheTokens(poolId, trancheId, currencyId, destinationAddress, amount); - // } - else if (Messages.isExecutedDecreaseInvestOrder(_msg)) { - ( - uint64 poolId, - bytes16 trancheId, - address investor, - uint128 currency, - uint128 currencyPayout - ) = Messages.parseExecutedDecreaseInvestOrder(_msg); - investmentManager.handleExecutedDecreaseInvestOrder( - poolId, trancheId, investor, currency, currencyPayout - ); + // } + else if (Messages.isExecutedDecreaseInvestOrder(_msg)) { + (uint64 poolId, bytes16 trancheId, address investor, uint128 currency, uint128 currencyPayout) = + Messages.parseExecutedDecreaseInvestOrder(_msg); + investmentManager.handleExecutedDecreaseInvestOrder(poolId, trancheId, investor, currency, currencyPayout); } else if (Messages.isExecutedDecreaseRedeemOrder(_msg)) { - ( - uint64 poolId, - bytes16 trancheId, - address investor, - uint128 currency, - uint128 trancheTokensPayout - ) = Messages.parseExecutedDecreaseRedeemOrder(_msg); + (uint64 poolId, bytes16 trancheId, address investor, uint128 currency, uint128 trancheTokensPayout) = + Messages.parseExecutedDecreaseRedeemOrder(_msg); investmentManager.handleExecutedDecreaseRedeemOrder( poolId, trancheId, investor, currency, trancheTokensPayout ); diff --git a/src/InvestmentManager.sol b/src/InvestmentManager.sol index a29ebed3..dffe76a7 100644 --- a/src/InvestmentManager.sol +++ b/src/InvestmentManager.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.18; pragma abicoder v2; -import { LiquidityPoolFactoryLike, MemberlistFactoryLike } from "./liquidityPool/Factory.sol"; -import { LiquidityPool } from "./liquidityPool/LiquidityPool.sol"; -import { ERC20Like } from "./token/restricted.sol"; -import { MemberlistLike } from "./token/memberlist.sol"; +import {LiquidityPoolFactoryLike, MemberlistFactoryLike} from "./liquidityPool/Factory.sol"; +import {LiquidityPool} from "./liquidityPool/LiquidityPool.sol"; +import {ERC20Like} from "./token/restricted.sol"; +import {MemberlistLike} from "./token/memberlist.sol"; import "./auth/auth.sol"; interface GatewayLike { @@ -36,19 +36,19 @@ interface GatewayLike { external; function collectInvest(uint64 poolId, bytes16 trancheId, address investor, uint128 currency) external; function collectRedeem(uint64 poolId, bytes16 trancheId, address investor, uint128 currency) external; - function paused() external returns(bool); + function paused() external returns (bool); } interface LiquidityPoolLike { // restricted token functions function memberlist() external returns (address); - function hasMember(address) external returns (bool); + function hasMember(address) external returns (bool); function file(bytes32 what, address data) external; // erc20 functions - function mint(address, uint) external; - function burn(address, uint) external; - function balanceOf(address) external returns (uint); - function transferFrom(address, address, uint) external returns (bool); + function mint(address, uint256) external; + function burn(address, uint256) external; + function balanceOf(address) external returns (uint256); + function transferFrom(address, address, uint256) external returns (bool); // 4626 functions function updateTokenPrice(uint128 _tokenPrice) external; function asset() external returns (address); @@ -77,10 +77,10 @@ struct Tranche { uint256 createdAt; string tokenName; string tokenSymbol; - address[] liquidityPools; - } + address[] liquidityPools; +} -/// @dev liquidity pool orders and deposit/redemption limits per user +/// @dev liquidity pool orders and deposit/redemption limits per user struct LPValues { uint128 maxDeposit; uint128 maxMint; @@ -89,11 +89,10 @@ struct LPValues { } contract InvestmentManager is Auth { - mapping(uint64 => Pool) public pools; // pools on centrifuge chain mapping(uint64 => mapping(bytes16 => Tranche)) public tranches; // centrifuge chain tranches mapping(uint64 => mapping(bytes16 => mapping(address => address))) public liquidityPools; // evm liquidity pools - pool & tranche & currency -> liquidity pool address - mapping(address => uint) public liquidityPoolWards; // access permissions liquidity pool invest / redeem functions + mapping(address => uint256) public liquidityPoolWards; // access permissions liquidity pool invest / redeem functions mapping(address => mapping(address => LPValues)) public orderbook; // liquidity pool orders & limits per user mapping(uint128 => address) public currencyIdToAddress; // chain agnostic currency id -> evm currency address @@ -104,7 +103,7 @@ contract InvestmentManager is Auth { EscrowLike public immutable escrow; // factories for liquidity pool deployments - LiquidityPoolFactoryLike public immutable liquidityPoolFactory; + LiquidityPoolFactoryLike public immutable liquidityPoolFactory; MemberlistFactoryLike public immutable memberlistFactory; uint256 constant MAX_UINT256 = type(uint256).max; @@ -114,7 +113,7 @@ contract InvestmentManager is Auth { event File(bytes32 indexed what, address data); event CurrencyAdded(uint128 indexed currency, address indexed currencyAddress); event PoolAdded(uint64 indexed poolId); - event PoolCurrencyAllowed(uint128 indexed currency, uint64 indexed poolId); + event PoolCurrencyAllowed(uint128 indexed currency, uint64 indexed poolId); event TrancheAdded(uint64 indexed poolId, bytes16 indexed trancheId); event TrancheDeployed(uint64 indexed poolId, bytes16 indexed trancheId, address indexed token); event DepositProcessed(address indexed liquidityPool, address indexed user, uint128 indexed currencyAmount); @@ -130,11 +129,15 @@ contract InvestmentManager is Auth { emit Rely(msg.sender); } - // --- Getters --- + // --- Getters --- /// @dev returns all existing liquidity pools for a centrifuge tranche - function getLiquidityPoolsForTranche(uint64 _poolId, bytes16 _trancheId) public view returns (address[] memory lPools) { - lPools = tranches[_poolId][_trancheId].liquidityPools; -} + function getLiquidityPoolsForTranche(uint64 _poolId, bytes16 _trancheId) + public + view + returns (address[] memory lPools) + { + lPools = tranches[_poolId][_trancheId].liquidityPools; + } /// @dev checks whether a Centrifuge pool is active - can be used to prevent deposit / redemption requests to/from certain pools & avoid transfers from escrow related to inactive pools. modifier poolActive() { @@ -156,7 +159,7 @@ contract InvestmentManager is Auth { } /// @dev liquidity pool must be message.sender. permissions check for liquidity pool gated functions. - modifier onlyLiquidityPoolWard() { + modifier onlyLiquidityPoolWard() { require(liquidityPoolWards[msg.sender] == 1, "InvestmentManager/not-liquidity-pool"); _; } @@ -169,59 +172,79 @@ contract InvestmentManager is Auth { } /// @dev activate / deactivate pool - function setPoolActive(uint64 _poolId, bool _isActive) external auth { + function setPoolActive(uint64 _poolId, bool _isActive) external auth { Pool storage pool = pools[_poolId]; require(pool.createdAt > 0, "InvestmentManager/invalid-pool"); pool.isActive = _isActive; } // --- liquidity pool outgoing message handling --- - /// @dev request tranche token redemption. Liquidity pools have to request redemptions from the centrifuge chain before actual currency payouts can be done. - /// The redemption requests are added to the order book on centrifuge chain. Once the next epoch is executed on centrifuge chain, liquidity pools can proceed with currency payouts in case their orders got fullfilled. + /// @dev request tranche token redemption. Liquidity pools have to request redemptions from the centrifuge chain before actual currency payouts can be done. + /// The redemption requests are added to the order book on centrifuge chain. Once the next epoch is executed on centrifuge chain, liquidity pools can proceed with currency payouts in case their orders got fullfilled. /// @notice The user tranche tokens required to fullfill the redemption request have to be locked, even though the currency payout can only happen after epoch execution. /// This function automatically closed all the outstading investment orders for the user. - function requestRedeem(uint256 _trancheTokenAmount, address _user) poolActive gatewayActive public onlyLiquidityPoolWard { + function requestRedeem(uint256 _trancheTokenAmount, address _user) + public + poolActive + gatewayActive + onlyLiquidityPoolWard + { address _liquidityPool = msg.sender; - LPValues storage lpValues = orderbook[_user][ _liquidityPool]; + LPValues storage lpValues = orderbook[_user][_liquidityPool]; LiquidityPoolLike lPool = LiquidityPoolLike(_liquidityPool); uint128 trancheTokenAmount = _toUint128(_trancheTokenAmount); - + // check if liquidity pool currency is supported by the centrifuge pool - require(_poolCurrencyCheck(lPool.poolId(), lPool.asset()), "InvestmentManager/currency-not-supported"); + require(_poolCurrencyCheck(lPool.poolId(), lPool.asset()), "InvestmentManager/currency-not-supported"); // check if user is allowed to hold the restriced liquidity pool tokens - require(_liquidityPoolTokensCheck(lPool.poolId(), lPool.trancheId(), lPool.asset(), _user), "InvestmentManager/tranche-tokens-not-supported"); - + require( + _liquidityPoolTokensCheck(lPool.poolId(), lPool.trancheId(), lPool.asset(), _user), + "InvestmentManager/tranche-tokens-not-supported" + ); + // todo: cancel outstanding order // gateway.decreaseInvestOrder(lPool.poolId(), lPool.trancheId(), _user, currencyAddressToId[lPool.asset()], lpValues.openInvest); // } - if(trancheTokenAmount == 0) { // case: outstanding deposit orders only needed to be cancelled + if (trancheTokenAmount == 0) { + // case: outstanding deposit orders only needed to be cancelled return; } - if(lpValues.maxMint >= trancheTokenAmount) { // case: user has unclaimed trancheTokens in escrow -> more than redemption request + if (lpValues.maxMint >= trancheTokenAmount) { + // case: user has unclaimed trancheTokens in escrow -> more than redemption request uint128 userTrancheTokenPrice = calcDepositTrancheTokenPrice(_user, _liquidityPool); uint128 currencyAmount = trancheTokenAmount * userTrancheTokenPrice; _decreaseDepositLimits(_user, _liquidityPool, currencyAmount, trancheTokenAmount); } else { - uint transferAmount = trancheTokenAmount - lpValues.maxMint; + uint256 transferAmount = trancheTokenAmount - lpValues.maxMint; lpValues.maxDeposit = 0; lpValues.maxMint = 0; // transfer the differene between required and locked tranche tokens from user to escrow require(lPool.balanceOf(_user) >= transferAmount, "InvestmentManager/insufficient-tranche-token-balance"); - require(lPool.transferFrom(_user, address(escrow), transferAmount), "InvestmentManager/tranche-token-transfer-failed"); - } - gateway.increaseRedeemOrder(lPool.poolId(), lPool.trancheId(), _user, currencyAddressToId[lPool.asset()], trancheTokenAmount); + require( + lPool.transferFrom(_user, address(escrow), transferAmount), + "InvestmentManager/tranche-token-transfer-failed" + ); + } + gateway.increaseRedeemOrder( + lPool.poolId(), lPool.trancheId(), _user, currencyAddressToId[lPool.asset()], trancheTokenAmount + ); } - - /// @dev request tranche token redemption. Liquidity pools have to request investments from the centrifuge chain before actual tranche token payouts can be done. - /// The deposit requests are added to the order book on centrifuge chain. Once the next epoch is executed on centrifuge chain, liquidity pools can proceed with tranche token payouts in case their orders got fullfilled. + + /// @dev request tranche token redemption. Liquidity pools have to request investments from the centrifuge chain before actual tranche token payouts can be done. + /// The deposit requests are added to the order book on centrifuge chain. Once the next epoch is executed on centrifuge chain, liquidity pools can proceed with tranche token payouts in case their orders got fullfilled. /// @notice The user currency amount equired to fullfill the deposit request have to be locked, even though the tranche token payout can only happen after epoch execution. /// This function automatically closed all the outstading redemption orders for the user. - function requestDeposit(uint _currencyAmount, address _user) poolActive gatewayActive public onlyLiquidityPoolWard { + function requestDeposit(uint256 _currencyAmount, address _user) + public + poolActive + gatewayActive + onlyLiquidityPoolWard + { address _liquidityPool = msg.sender; - LPValues storage lpValues = orderbook[_user][ _liquidityPool]; + LPValues storage lpValues = orderbook[_user][_liquidityPool]; LiquidityPoolLike lPool = LiquidityPoolLike(_liquidityPool); ERC20Like currency = ERC20Like(lPool.asset()); uint128 currencyAmount = _toUint128(_currencyAmount); @@ -229,16 +252,21 @@ contract InvestmentManager is Auth { // check if liquidity pool currency is supported by the centrifuge pool require(_poolCurrencyCheck(lPool.poolId(), lPool.asset()), "InvestmentManager/currency-not-supported"); // check if user is allowed to hold the restriced liquidity pool tokens - require(_liquidityPoolTokensCheck(lPool.poolId(), lPool.trancheId(), lPool.asset(), _user), "InvestmentManager/tranche-tokens-not-supported"); + require( + _liquidityPoolTokensCheck(lPool.poolId(), lPool.trancheId(), lPool.asset(), _user), + "InvestmentManager/tranche-tokens-not-supported" + ); // todo: cancel outstanding order // gateway.decreaseRedeemOrder(lPool.poolId(), lPool.trancheId(), _user, currencyAddressToId[lPool.asset()], lpValues.openRedeem); - if(currencyAmount == 0) { // case: outstanding redemption orders only needed to be cancelled - return; + if (currencyAmount == 0) { + // case: outstanding redemption orders only needed to be cancelled + return; } - if(lpValues.maxWithdraw >= currencyAmount) { // case: user has some claimable funds in escrow -> funds > depositRequest currencyAmount - uint128 userTrancheTokenPrice = calcRedeemTrancheTokenPrice( _user, _liquidityPool); + if (lpValues.maxWithdraw >= currencyAmount) { + // case: user has some claimable funds in escrow -> funds > depositRequest currencyAmount + uint128 userTrancheTokenPrice = calcRedeemTrancheTokenPrice(_user, _liquidityPool); uint128 trancheTokens = currencyAmount / userTrancheTokenPrice; _decreaseRedemptionLimits(_user, _liquidityPool, currencyAmount, trancheTokens); } else { @@ -248,27 +276,38 @@ contract InvestmentManager is Auth { // transfer the differene between required and locked currency from user to escrow require(currency.balanceOf(_user) >= transferAmount, "InvestmentManager/insufficient-balance"); - require(currency.transferFrom(_user, address(escrow), transferAmount), "InvestmentManager/currency-transfer-failed"); - } - gateway.increaseInvestOrder(lPool.poolId(), lPool.trancheId(), _user, currencyAddressToId[lPool.asset()], currencyAmount); + require( + currency.transferFrom(_user, address(escrow), transferAmount), + "InvestmentManager/currency-transfer-failed" + ); + } + gateway.increaseInvestOrder( + lPool.poolId(), lPool.trancheId(), _user, currencyAddressToId[lPool.asset()], currencyAmount + ); } - // --- public outgoing message handling --- + // --- public outgoing message handling --- - function collectInvest(uint64 _poolId, bytes16 _trancheId, address _user, address _currency) public onlyLiquidityPoolWard { + function collectInvest(uint64 _poolId, bytes16 _trancheId, address _user, address _currency) + public + onlyLiquidityPoolWard + { LiquidityPoolLike lPool = LiquidityPoolLike(msg.sender); require(lPool.hasMember(_user), "InvestmentManager/not-a-member"); require(_poolCurrencyCheck(_poolId, _currency), "InvestmentManager/currency-not-supported"); gateway.collectInvest(_poolId, _trancheId, _user, currencyAddressToId[_currency]); } - function collectRedeem(uint64 _poolId, bytes16 _trancheId, address _user, address _currency) public onlyLiquidityPoolWard { + function collectRedeem(uint64 _poolId, bytes16 _trancheId, address _user, address _currency) + public + onlyLiquidityPoolWard + { LiquidityPoolLike lPool = LiquidityPoolLike(msg.sender); require(lPool.hasMember(_user), "InvestmentManager/not-a-member"); require(_poolCurrencyCheck(_poolId, _currency), "InvestmentManager/currency-not-supported"); gateway.collectRedeem(_poolId, _trancheId, _user, currencyAddressToId[_currency]); } - + function transfer(address currencyAddress, bytes32 recipient, uint128 amount) public { uint128 currency = currencyAddressToId[currencyAddress]; require(currency != 0, "InvestmentManager/unknown-currency"); @@ -347,7 +386,7 @@ contract InvestmentManager is Auth { emit PoolAdded(poolId); } - /// @dev centrifuge pools can support multiple currencies for investing. this function adds a new supported currency to the pool details. + /// @dev centrifuge pools can support multiple currencies for investing. this function adds a new supported currency to the pool details. /// Adding new currencies allow the creation of new liquidity pools for the underlying centrifuge chain pool. /// @notice the function can only be executed by the gateway contract. function allowPoolCurrency(uint64 poolId, uint128 currency) public onlyGateway { @@ -375,21 +414,21 @@ contract InvestmentManager is Auth { require(pool.createdAt > 0, "InvestmentManager/invalid-pool"); Tranche storage tranche = tranches[_poolId][_trancheId]; require(tranche.createdAt == 0, "InvestmentManager/tranche-already-exists"); - + tranche.poolId = _poolId; tranche.trancheId = _trancheId; tranche.decimals = _decimals; tranche.tokenName = _tokenName; tranche.tokenSymbol = _tokenSymbol; tranche.createdAt = block.timestamp; - + emit TrancheAdded(_poolId, _trancheId); } - + function updateTokenPrice(uint64 _poolId, bytes16 _trancheId, uint128 _price) public onlyGateway { Tranche storage tranche = tranches[_poolId][_trancheId]; require(tranche.createdAt > 0, "InvestmentManager/invalid-pool-or-tranche"); - for (uint i=0; i 0, "InvestmentManager/invalid-pool-or-tranche"); - for (uint i=0; i 0), "LiquidityPool/amount-exceeds-deposit-limits"); uint128 trancheTokenAmount = currencyAmount / userTrancheTokenPriceLP; _decreaseDepositLimits(_user, _liquidityPool, currencyAmount, trancheTokenAmount); // decrease user's deposit limits for this lp - require(lPool.hasMember( _user), "InvestmentManager/trancheTokens-not-a-member"); - require(lPool.transferFrom(address(escrow), _user, trancheTokenAmount), "InvestmentManager/trancheTokens-transfer-failed"); - + require(lPool.hasMember(_user), "InvestmentManager/trancheTokens-not-a-member"); + require( + lPool.transferFrom(address(escrow), _user, trancheTokenAmount), + "InvestmentManager/trancheTokens-transfer-failed" + ); + emit DepositProcessed(_liquidityPool, _user, currencyAmount); return uint256(trancheTokenAmount); } @@ -539,22 +615,34 @@ contract InvestmentManager is Auth { /// Note: The tranche tokens are already minted on collectInvest and are deposited to the escrow account until the users calls mint, or deposit. /// @notice currencyAmount return value is type of uint256 to be compliant with EIP4626 LiquidityPool interface /// @return currencyAmount the amount of liquidityPool assets invested and locked in escrow in order for the amount of tranche received after successful investment into the pool. - function processMint(address _user, uint256 _trancheTokenAmount) poolActive gatewayActive public onlyLiquidityPoolWard returns (uint256) { + function processMint(address _user, uint256 _trancheTokenAmount) + public + poolActive + gatewayActive + onlyLiquidityPoolWard + returns (uint256) + { address _liquidityPool = msg.sender; uint128 trancheTokenAmount = _toUint128(_trancheTokenAmount); LiquidityPoolLike lPool = LiquidityPoolLike(_liquidityPool); - require((trancheTokenAmount <= orderbook[_user][ _liquidityPool].maxMint), "InvestmentManager/amount-exceeds-mint-limits"); - + require( + (trancheTokenAmount <= orderbook[_user][_liquidityPool].maxMint), + "InvestmentManager/amount-exceeds-mint-limits" + ); + uint128 userTrancheTokenPriceLP = calcDepositTrancheTokenPrice(_user, _liquidityPool); require((userTrancheTokenPriceLP > 0), "LiquidityPool/amount-exceeds-mint-limits"); uint128 currencyAmount = trancheTokenAmount * userTrancheTokenPriceLP; - _decreaseDepositLimits(_user, _liquidityPool, currencyAmount, trancheTokenAmount); // decrease the possible deposit limits - require(lPool.hasMember( _user), "InvestmentManager/trancheTokens-not-a-member"); - require(lPool.transferFrom(address(escrow), _user, trancheTokenAmount), "InvestmentManager/trancheTokens-transfer-failed"); + _decreaseDepositLimits(_user, _liquidityPool, currencyAmount, trancheTokenAmount); // decrease the possible deposit limits + require(lPool.hasMember(_user), "InvestmentManager/trancheTokens-not-a-member"); + require( + lPool.transferFrom(address(escrow), _user, trancheTokenAmount), + "InvestmentManager/trancheTokens-transfer-failed" + ); emit DepositProcessed(_liquidityPool, _user, currencyAmount); - return uint256(currencyAmount); + return uint256(currencyAmount); } /// @dev processes user's trancheToken redemption after the epoch has been executed on Centrifuge chain. @@ -562,21 +650,33 @@ contract InvestmentManager is Auth { /// Note: The trancheToken amount required to fullfill the redemption order was already locked in escrow upon calling requestRedeem and burned upon collectRedeem. /// @notice currencyAmount return value is type of uint256 to be compliant with EIP4626 LiquidityPool interface /// @return currencyAmount the amount of liquidityPool assets received for the amount of redeemed/burned trancheTokens. - function processRedeem(uint256 _trancheTokenAmount, address _receiver, address _user) poolActive gatewayActive public onlyLiquidityPoolWard returns (uint256) { + function processRedeem(uint256 _trancheTokenAmount, address _receiver, address _user) + public + poolActive + gatewayActive + onlyLiquidityPoolWard + returns (uint256) + { address _liquidityPool = msg.sender; uint128 trancheTokenAmount = _toUint128(_trancheTokenAmount); LiquidityPoolLike lPool = LiquidityPoolLike(_liquidityPool); - require((trancheTokenAmount <= orderbook[_user][ _liquidityPool].maxRedeem), "InvestmentManager/amount-exceeds-redeem-limits"); + require( + (trancheTokenAmount <= orderbook[_user][_liquidityPool].maxRedeem), + "InvestmentManager/amount-exceeds-redeem-limits" + ); uint128 userTrancheTokenPriceLP = calcRedeemTrancheTokenPrice(_user, _liquidityPool); require((userTrancheTokenPriceLP > 0), "LiquidityPool/amount-exceeds-redemption-limits"); uint128 currencyAmount = trancheTokenAmount * userTrancheTokenPriceLP; - - _decreaseRedemptionLimits(_user, _liquidityPool, currencyAmount, trancheTokenAmount); // decrease the possible deposit limits - require(ERC20Like(lPool.asset()).transferFrom(address(escrow), _receiver, currencyAmount), "InvestmentManager/shares-transfer-failed"); - + + _decreaseRedemptionLimits(_user, _liquidityPool, currencyAmount, trancheTokenAmount); // decrease the possible deposit limits + require( + ERC20Like(lPool.asset()).transferFrom(address(escrow), _receiver, currencyAmount), + "InvestmentManager/shares-transfer-failed" + ); + emit RedemptionProcessed(_liquidityPool, _user, trancheTokenAmount); - return uint256(currencyAmount); + return uint256(currencyAmount); } /// @dev processes user's trancheToken redemption after the epoch has been executed on Centrifuge chain. @@ -584,28 +684,35 @@ contract InvestmentManager is Auth { /// Note: The trancheToken amount required to fullfill the redemption order was already locked in escrow upon calling requestRedeem and burned upon collectRedeem. /// @notice trancheTokenAmount return value is type of uint256 to be compliant with EIP4626 LiquidityPool interface /// @return trancheTokenAmount the amount of trancheTokens redeemed/burned required to receive the currencyAmount payout/withdrawel. - function processWithdraw(uint256 _currencyAmount, address _receiver, address _user) poolActive gatewayActive public onlyLiquidityPoolWard returns (uint256) { + function processWithdraw(uint256 _currencyAmount, address _receiver, address _user) + public + poolActive + gatewayActive + onlyLiquidityPoolWard + returns (uint256) + { address _liquidityPool = msg.sender; uint128 currencyAmount = _toUint128(_currencyAmount); LiquidityPoolLike lPool = LiquidityPoolLike(_liquidityPool); - require((currencyAmount <= orderbook[_user][ _liquidityPool].maxWithdraw), "InvestmentManager/amount-exceeds-withdraw-limits"); + require( + (currencyAmount <= orderbook[_user][_liquidityPool].maxWithdraw), + "InvestmentManager/amount-exceeds-withdraw-limits" + ); uint128 userTrancheTokenPriceLP = calcRedeemTrancheTokenPrice(_user, _liquidityPool); require((userTrancheTokenPriceLP > 0), "LiquidityPool/amount-exceeds-withdraw-limits"); uint128 trancheTokenAmount = currencyAmount / userTrancheTokenPriceLP; - _decreaseRedemptionLimits(_user, _liquidityPool, currencyAmount, trancheTokenAmount); - require(ERC20Like(lPool.asset()).transferFrom(address(escrow), _receiver, currencyAmount), "InvestmentManager/trancheTokens-transfer-failed"); + _decreaseRedemptionLimits(_user, _liquidityPool, currencyAmount, trancheTokenAmount); + require( + ERC20Like(lPool.asset()).transferFrom(address(escrow), _receiver, currencyAmount), + "InvestmentManager/trancheTokens-transfer-failed" + ); return uint256(trancheTokenAmount); } // ----- public functions - function deployLiquidityPool( - uint64 _poolId, - bytes16 _trancheId, - address _currency - ) public returns (address) { - + function deployLiquidityPool(uint64 _poolId, bytes16 _trancheId, address _currency) public returns (address) { address liquidityPool = liquidityPools[_poolId][_trancheId][_currency]; require(liquidityPool == address(0), "InvestmentManager/liquidityPool-already-deployed"); require(pools[_poolId].createdAt > 0, "InvestmentManager/pool-does-not-exist"); @@ -617,32 +724,51 @@ contract InvestmentManager is Auth { // deploy liquidity pool set gateway as admin on liquidityPool & memberlist address memberlist = memberlistFactory.newMemberlist(address(gateway), address(this)); MemberlistLike(memberlist).updateMember(address(escrow), type(uint256).max); // add escrow to tranche tokens memberlist - liquidityPool = liquidityPoolFactory.newLiquidityPool(_poolId, _trancheId, currencyId, _currency, address(this), address(gateway), memberlist, tranche.tokenName, tranche.tokenSymbol, tranche.decimals); + liquidityPool = liquidityPoolFactory.newLiquidityPool( + _poolId, + _trancheId, + currencyId, + _currency, + address(this), + address(gateway), + memberlist, + tranche.tokenName, + tranche.tokenSymbol, + tranche.decimals + ); liquidityPools[_poolId][_trancheId][_currency] = liquidityPool; liquidityPoolWards[liquidityPool] = 1; // give liquidityPool permissions, so that invest & redeem functions can be called tranche.liquidityPools.push(liquidityPool); - // enable connectors to take the liquidity pool tokens out of escrow in case if investments + // enable connectors to take the liquidity pool tokens out of escrow in case if investments EscrowLike(escrow).approve(liquidityPool, address(this), MAX_UINT256); - + emit LiquidityPoolDeployed(_poolId, _trancheId, liquidityPool); return liquidityPool; } - - // ------ helper functions - // TODO: check rounding - function calcDepositTrancheTokenPrice(address _user, address _liquidityPool) public view returns (uint128 userTrancheTokenPrice) { + + // ------ helper functions + // TODO: check rounding + function calcDepositTrancheTokenPrice(address _user, address _liquidityPool) + public + view + returns (uint128 userTrancheTokenPrice) + { LPValues storage lpValues = orderbook[_user][_liquidityPool]; - if(lpValues.maxMint == 0) { + if (lpValues.maxMint == 0) { return 0; - } + } userTrancheTokenPrice = lpValues.maxDeposit / lpValues.maxMint; } - function calcRedeemTrancheTokenPrice(address _user, address _liquidityPool) public view returns (uint128 userTrancheTokenPrice) { + function calcRedeemTrancheTokenPrice(address _user, address _liquidityPool) + public + view + returns (uint128 userTrancheTokenPrice) + { LPValues storage lpValues = orderbook[_user][_liquidityPool]; - if(lpValues.maxRedeem == 0) { + if (lpValues.maxRedeem == 0) { return 0; - } + } userTrancheTokenPrice = lpValues.maxWithdraw / lpValues.maxRedeem; } @@ -652,15 +778,20 @@ contract InvestmentManager is Auth { require(allowedPoolCurrencies[_poolId][_currencyAddress], "InvestmentManager/pool-currency-not-allowed"); return true; } - - function _liquidityPoolTokensCheck(uint64 _poolId, bytes16 _trancheId, address _currency, address _user) internal returns (bool) { + + function _liquidityPoolTokensCheck(uint64 _poolId, bytes16 _trancheId, address _currency, address _user) + internal + returns (bool) + { LiquidityPoolLike lPool = LiquidityPoolLike(liquidityPools[_poolId][_trancheId][_currency]); require(address(lPool) != address(0), "InvestmentManager/unknown-liquidity-pool"); require(lPool.hasMember(_user), "InvestmentManager/not-a-member"); return true; } - function _decreaseDepositLimits(address _user, address _liquidityPool, uint128 _currency, uint128 _trancheTokens) internal { + function _decreaseDepositLimits(address _user, address _liquidityPool, uint128 _currency, uint128 _trancheTokens) + internal + { LPValues storage values = orderbook[_user][_liquidityPool]; if (values.maxDeposit < _currency) { values.maxDeposit = 0; @@ -670,11 +801,13 @@ contract InvestmentManager is Auth { if (values.maxMint < _trancheTokens) { values.maxMint = 0; } else { - values.maxMint = values.maxMint - _trancheTokens; + values.maxMint = values.maxMint - _trancheTokens; } } - function _decreaseRedemptionLimits(address _user, address _liquidityPool, uint128 _currency, uint128 _trancheTokens) internal { + function _decreaseRedemptionLimits(address _user, address _liquidityPool, uint128 _currency, uint128 _trancheTokens) + internal + { LPValues storage values = orderbook[_user][_liquidityPool]; if (values.maxWithdraw < _currency) { values.maxWithdraw = 0; @@ -684,7 +817,7 @@ contract InvestmentManager is Auth { if (values.maxRedeem < _trancheTokens) { values.maxRedeem = 0; } else { - values.maxRedeem = values.maxRedeem - _trancheTokens; + values.maxRedeem = values.maxRedeem - _trancheTokens; } } diff --git a/src/Messages.sol b/src/Messages.sol index 5725f554..59a9e47b 100644 --- a/src/Messages.sol +++ b/src/Messages.sol @@ -314,7 +314,14 @@ library Messages { uint128 amount ) internal pure returns (bytes memory) { return abi.encodePacked( - uint8(Call.TransferTrancheTokens), poolId, trancheId, sender, destinationDomain, currencyId, destinationAddress, amount + uint8(Call.TransferTrancheTokens), + poolId, + trancheId, + sender, + destinationDomain, + currencyId, + destinationAddress, + amount ); } @@ -334,7 +341,7 @@ library Messages { return formatTransferTrancheTokens( poolId, trancheId, sender, destinationDomain, currencyId, bytes32(bytes20(destinationAddress)), amount ); - } + } function isTransferTrancheTokens(bytes29 _msg) internal pure returns (bool) { return messageType(_msg) == Call.TransferTrancheTokens; @@ -362,7 +369,7 @@ library Messages { destinationAddress = bytes32((_msg.index(82, 20))); amount = uint128(_msg.indexUint(114, 16)); } - + // Parse a TransferTrancheTokens to an EVM-based `destinationAddress` (20-byte long). // We ignore the `sender` and the `domain` since it's not relevant when parsing an incoming message. function parseTransferTrancheTokens20(bytes29 _msg) @@ -372,7 +379,7 @@ library Messages { { poolId = uint64(_msg.indexUint(1, 8)); trancheId = bytes16(_msg.index(9, 16)); - + // ignore: `sender` at bytes 25-56 // ignore: `domain` at bytes 57-65 currencyId = uint128(_msg.indexUint(66, 16)); @@ -572,7 +579,6 @@ library Messages { trancheId = bytes16(_msg.index(9, 16)); investor = bytes32(_msg.index(25, 32)); currency = uint128(_msg.indexUint(57, 16)); - } function formatExecutedDecreaseInvestOrder( @@ -583,12 +589,7 @@ library Messages { uint128 currencyPayout ) internal pure returns (bytes memory) { return abi.encodePacked( - uint8(Call.ExecutedDecreaseInvestOrder), - poolId, - trancheId, - investor, - currency, - currencyPayout + uint8(Call.ExecutedDecreaseInvestOrder), poolId, trancheId, investor, currency, currencyPayout ); } @@ -599,13 +600,7 @@ library Messages { function parseExecutedDecreaseInvestOrder(bytes29 _msg) internal pure - returns ( - uint64 poolId, - bytes16 trancheId, - address investor, - uint128 currency, - uint128 currencyPayout - ) + returns (uint64 poolId, bytes16 trancheId, address investor, uint128 currency, uint128 currencyPayout) { poolId = uint64(_msg.indexUint(1, 8)); trancheId = bytes16(_msg.index(9, 16)); @@ -622,12 +617,7 @@ library Messages { uint128 currencyPayout ) internal pure returns (bytes memory) { return abi.encodePacked( - uint8(Call.ExecutedDecreaseRedeemOrder), - poolId, - trancheId, - investor, - currency, - currencyPayout + uint8(Call.ExecutedDecreaseRedeemOrder), poolId, trancheId, investor, currency, currencyPayout ); } @@ -638,13 +628,7 @@ library Messages { function parseExecutedDecreaseRedeemOrder(bytes29 _msg) internal pure - returns ( - uint64 poolId, - bytes16 trancheId, - address investor, - uint128 currency, - uint128 trancheTokensPayout - ) + returns (uint64 poolId, bytes16 trancheId, address investor, uint128 currency, uint128 trancheTokensPayout) { poolId = uint64(_msg.indexUint(1, 8)); trancheId = bytes16(_msg.index(9, 16)); diff --git a/src/admin/PauseAdmin.sol b/src/admin/PauseAdmin.sol index b538fcbb..b1e28468 100644 --- a/src/admin/PauseAdmin.sol +++ b/src/admin/PauseAdmin.sol @@ -8,7 +8,6 @@ import "./../auth/auth.sol"; contract PauseAdmin is Auth { Gateway public gateway; - // --- Events --- event File(bytes32 indexed what, address indexed data); diff --git a/src/auth/auth.sol b/src/auth/auth.sol index 165eeedc..d6b2726c 100644 --- a/src/auth/auth.sol +++ b/src/auth/auth.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.18; contract Auth { - mapping (address => uint256) public wards; - + mapping(address => uint256) public wards; + event Rely(address indexed usr); event Deny(address indexed usr); @@ -12,13 +12,14 @@ contract Auth { wards[usr] = 1; emit Rely(usr); } + function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); } - modifier auth { + modifier auth() { require(wards[msg.sender] == 1, "not-authorized"); _; } -} \ No newline at end of file +} diff --git a/src/liquidityPool/Factory.sol b/src/liquidityPool/Factory.sol index 1b9a6606..dec2d136 100644 --- a/src/liquidityPool/Factory.sol +++ b/src/liquidityPool/Factory.sol @@ -1,22 +1,41 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.18; -import { LiquidityPool } from "./LiquidityPool.sol"; -import { Memberlist} from "../token/memberlist.sol"; +import {LiquidityPool} from "./LiquidityPool.sol"; +import {Memberlist} from "../token/memberlist.sol"; interface ImmutableCreate2Factory { function safeCreate2(bytes32 salt, bytes calldata initCode) external payable returns (address deploymentAddress); } interface LiquidityPoolFactoryLike { - function newLiquidityPool(uint64 _poolId, bytes16 _trancheId, uint128 _currencyId, address _asset, address _investmentManager, address _admin, address _memberlist, string memory _name, string memory _symbol, uint8 _decimals) external returns (address); + function newLiquidityPool( + uint64 _poolId, + bytes16 _trancheId, + uint128 _currencyId, + address _asset, + address _investmentManager, + address _admin, + address _memberlist, + string memory _name, + string memory _symbol, + uint8 _decimals + ) external returns (address); } contract LiquidityPoolFactory { - function newLiquidityPool(uint64 _poolId, bytes16 _trancheId, uint128 _currencyId, address _asset, address _investmentManager, address _admin, address _memberlist, string memory _name, string memory _symbol, uint8 _decimals) - public - returns (address) - { + function newLiquidityPool( + uint64 _poolId, + bytes16 _trancheId, + uint128 _currencyId, + address _asset, + address _investmentManager, + address _admin, + address _memberlist, + string memory _name, + string memory _symbol, + uint8 _decimals + ) public returns (address) { // Salt is hash(poolId + trancheId + asset), to deploy copies of the liquidity pool contract // on multiple chains with the same address for the same tranche and asset bytes32 salt = keccak256(abi.encodePacked(_poolId, _trancheId, _currencyId)); @@ -49,10 +68,9 @@ contract MemberlistFactory { function newMemberlist(address _admin, address _investmentManager) public returns (address memberList) { Memberlist memberlist = new Memberlist(); - memberlist.deny(msg.sender); memberlist.rely(_admin); - memberlist.rely(_investmentManager); + memberlist.rely(_investmentManager); memberlist.deny(address(this)); return (address(memberlist)); diff --git a/src/liquidityPool/LiquidityPool.sol b/src/liquidityPool/LiquidityPool.sol index dd2496ea..828814f8 100644 --- a/src/liquidityPool/LiquidityPool.sol +++ b/src/liquidityPool/LiquidityPool.sol @@ -1,17 +1,17 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.18; -// Liquidity Pool implementation for Centrifuge Pools following the EIP4626 standard. +// Liquidity Pool implementation for Centrifuge Pools following the EIP4626 standard. // Each Liquidity Pool is a tokenized vault issuing shares as restricted ERC20 tokens against stable currency deposits based on the current share price. // Liquidity Pool vault: Liquidity Pool asset value. // asset: The underlying stable currency of the Liquidity Pool. Note: 1 Centrifuge Pool can have multiple Liquidity Pools for the same Tranche token with different underlying currencies (assets). -// share: The restricted ERC-20 Liquidity pool token. Has a ratio (token price) of underlying assets exchanged on deposit/withdraw/redeem. Liquidity pool tokens on evm represent tranche tokens on centrifuge chain (even though in the current implementation one tranche token on centrifuge chain can be split across multiple liquidity pool tokens on EVM). +// share: The restricted ERC-20 Liquidity pool token. Has a ratio (token price) of underlying assets exchanged on deposit/withdraw/redeem. Liquidity pool tokens on evm represent tranche tokens on centrifuge chain (even though in the current implementation one tranche token on centrifuge chain can be split across multiple liquidity pool tokens on EVM). -// Challenges: -// 1. Centrifuge Pools and corresponding Tranches live on Centchain having their liquidity spread across multiple chains. +// Challenges: +// 1. Centrifuge Pools and corresponding Tranches live on Centchain having their liquidity spread across multiple chains. // Latest Tranche Token token price is not available in the same block and is updated in an async manner from Centrifuge chain. Deposit & Redemption previews can only be made based on the latest price updates from Centrifuge chain. // 2. Pool Epochs: Deposits into and redemptions from Centrifuge Pools are subject to epochs. Deposit and redemption orders are collected during 24H epoch periods -// and filled during epoch execution following the rules of the underlying pool. Consequently, deposits and redemptions are not instanty possible and have to follow the epoch schedule. +// and filled during epoch execution following the rules of the underlying pool. Consequently, deposits and redemptions are not instanty possible and have to follow the epoch schedule. // LiquidityPool is extending the EIP4626 standard by 'requestRedeem' & 'requestDeposit' functions, where redeem and deposit orders are submitted to the pools to be included in the execution of the following epoch. // After execution users can use the redeem and withdraw functions to get their shares and/or assets from the pools. @@ -19,7 +19,6 @@ pragma solidity ^0.8.18; // maple: https://github.com/maple-labs/pool-v2/blob/301f05b4fe5e9202eef988b4c8321310b4e86dc8/contracts/Pool.sol // yearn: https://github.com/yearn/yearn-vaults-v3/blob/master/contracts/VaultV3.vy - import "../token/restricted.sol"; interface InvestmentManagerLike { @@ -35,13 +34,11 @@ interface InvestmentManagerLike { function requestDeposit(uint256 _assets, address _receiver) external; function collectInvest(uint64 poolId, bytes16 trancheId, address receiver, address currency) external; function collectRedeem(uint64 poolId, bytes16 trancheId, address receiver, address currency) external; - } /// @title LiquidityPool /// @author ilinzweilin contract LiquidityPool is RestrictedToken { - InvestmentManagerLike public investmentManager; address public asset; // underlying stable ERC-20 stable currency @@ -52,15 +49,17 @@ contract LiquidityPool is RestrictedToken { // ids of the existing centrifuge chain pool and tranche that the liquidity pool belongs to uint64 public poolId; bytes16 public trancheId; - + // events event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); - event Withdraw(address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares); - + event Withdraw( + address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares + ); + constructor(uint8 _decimals) RestrictedToken(_decimals) {} /// @dev investmentManager and asset address to be filed by the factory on deployment - function file(bytes32 _what, address _data) override public auth { + function file(bytes32 _what, address _data) public override auth { if (_what == "investmentManager") investmentManager = InvestmentManagerLike(_data); else if (_what == "asset") asset = _data; else if (_what == "memberlist") memberlist = MemberlistLike(_data); @@ -78,7 +77,7 @@ contract LiquidityPool is RestrictedToken { /// @dev The total amount of vault shares /// @return Total amount of the underlying vault assets including accrued interest function totalAssets() public view returns (uint256) { - return totalSupply * latestPrice; + return totalSupply * latestPrice; } /// @dev Calculates the amount of shares / tranche tokens that any user would get for the amount of assets provided. The calcultion is based on the token price from the most recent epoch retrieved from Centrifuge chain. @@ -109,7 +108,7 @@ contract LiquidityPool is RestrictedToken { /// @dev collect shares for deposited funds after pool epoch execution. maxMint is the max amount of shares that can be collected. Required assets must already be locked /// maxDeposit is the amount of funds that was successfully invested into the pool on Centrifuge chain function deposit(uint256 _assets, address _receiver) public returns (uint256 shares) { - shares = investmentManager.processDeposit( _receiver, _assets); + shares = investmentManager.processDeposit(_receiver, _assets); emit Deposit(address(this), _receiver, _assets, shares); } @@ -117,13 +116,13 @@ contract LiquidityPool is RestrictedToken { /// maxDeposit is the amount of funds that was successfully invested into the pool on Centrifuge chain function mint(uint256 _shares, address _receiver) public returns (uint256 assets) { // require(_receiver == msg.sender, "LiquidityPool/not-authorized-to-mint"); - assets = investmentManager.processMint(_receiver, _shares); + assets = investmentManager.processMint(_receiver, _shares); emit Deposit(address(this), _receiver, assets, _shares); } /// @dev Maximum amount of shares that can be claimed by the receiver after the epoch has been executed on the Centrifuge chain side. function maxMint(address _receiver) external view returns (uint256 maxShares) { - maxShares = investmentManager.maxMint(_receiver, address(this)); + maxShares = investmentManager.maxMint(_receiver, address(this)); } /// @return assets that any user would get for an amount of shares provided -> convertToAssets @@ -140,7 +139,7 @@ contract LiquidityPool is RestrictedToken { function maxWithdraw(address _receiver) public view returns (uint256 maxAssets) { return investmentManager.maxWithdraw(_receiver, address(this)); } - + /// @return shares that a user would need to redeem in order to receive the given amount of assets -> convertToAssets function previewWithdraw(uint256 _assets) public view returns (uint256 shares) { shares = convertToShares(_assets); @@ -151,14 +150,14 @@ contract LiquidityPool is RestrictedToken { function withdraw(uint256 _assets, address _receiver, address _owner) public returns (uint256 shares) { // check if messgae sender can spend owners funds require(_owner == msg.sender, "LiquidityPool/not-authorized-to-withdraw"); - uint sharesRedeemed = investmentManager.processWithdraw( _assets, _receiver, _owner); + uint256 sharesRedeemed = investmentManager.processWithdraw(_assets, _receiver, _owner); emit Withdraw(address(this), _receiver, _owner, _assets, sharesRedeemed); return sharesRedeemed; } /// @dev Max amount of shares that can be redeemed by the owner after redemption was requested function maxRedeem(address _owner) public view returns (uint256 maxShares) { - return investmentManager.maxRedeem(_owner, address(this)); + return investmentManager.maxRedeem(_owner, address(this)); } /// @return assets that any user could redeem for an given amount of shares -> convertToAssets @@ -170,7 +169,7 @@ contract LiquidityPool is RestrictedToken { /// @return assets currency payout for the exact amount of redeemed _shares function redeem(uint256 _shares, address _receiver, address _owner) public returns (uint256 assets) { require(_owner == msg.sender, "LiquidityPool/not-authorized-to-redeem"); - uint currencyPayout = investmentManager.processRedeem(_shares, _receiver, _owner); + uint256 currencyPayout = investmentManager.processRedeem(_shares, _receiver, _owner); emit Withdraw(address(this), _receiver, _owner, currencyPayout, _shares); return currencyPayout; } @@ -189,4 +188,3 @@ contract LiquidityPool is RestrictedToken { investmentManager.collectInvest(poolId, trancheId, _receiver, asset); } } - diff --git a/src/routers/axelar/EVMRouter.sol b/src/routers/axelar/EVMRouter.sol index 0deece08..bcae393e 100644 --- a/src/routers/axelar/EVMRouter.sol +++ b/src/routers/axelar/EVMRouter.sol @@ -14,8 +14,13 @@ interface InvestmentManagerLike { ) external; function updateMember(uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) external; function updateTokenPrice(uint64 poolId, bytes16 trancheId, uint128 price) external; - function handleTransferTrancheTokens(uint64 poolId, bytes16 trancheId, uint128 currencyId, address destinationAddress, uint128 amount) - external; + function handleTransferTrancheTokens( + uint64 poolId, + bytes16 trancheId, + uint128 currencyId, + address destinationAddress, + uint128 amount + ) external; } interface AxelarExecutableLike { diff --git a/src/token/erc20.sol b/src/token/erc20.sol index faef2681..c4fd4907 100644 --- a/src/token/erc20.sol +++ b/src/token/erc20.sol @@ -35,7 +35,7 @@ contract ERC20 is Auth { constructor(uint8 decimals_) { decimals = decimals_; wards[msg.sender] = 1; - + deploymentChainId = block.chainid; _DOMAIN_SEPARATOR = _calculateDomainSeparator(block.chainid); } diff --git a/src/token/memberlist.sol b/src/token/memberlist.sol index d5adefce..a4db1be0 100644 --- a/src/token/memberlist.sol +++ b/src/token/memberlist.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.18; + import "./../auth/auth.sol"; interface MemberlistLike { @@ -9,6 +10,7 @@ interface MemberlistLike { contract Memberlist is Auth { mapping(address => uint256) public members; + constructor() { wards[msg.sender] = 1; emit Rely(msg.sender); diff --git a/src/token/restricted.sol b/src/token/restricted.sol index af48c548..791deba1 100644 --- a/src/token/restricted.sol +++ b/src/token/restricted.sol @@ -33,7 +33,7 @@ contract RestrictedToken is ERC20 { // --- Events --- event File(bytes32 indexed what, address data); - constructor(uint8 decimals_) ERC20(decimals_) { } + constructor(uint8 decimals_) ERC20(decimals_) {} modifier checkMember(address user) { memberlist.member(user); diff --git a/test/Admin.t.sol b/test/Admin.t.sol index 8e38c27f..f4496e33 100644 --- a/test/Admin.t.sol +++ b/test/Admin.t.sol @@ -227,7 +227,6 @@ contract AdminTest is Test { assertEq(gateway.wards(spell), 1); } - function testShortRelyFailsBefore24hours() public { address spell = vm.addr(1); centChainLiquidityPools.incomingScheduleUpgrade(spell); diff --git a/test/InvestmentManager.t.sol b/test/InvestmentManager.t.sol index e548820f..c6c55ba4 100644 --- a/test/InvestmentManager.t.sol +++ b/test/InvestmentManager.t.sol @@ -2,19 +2,19 @@ pragma solidity ^0.8.18; pragma abicoder v2; -import { InvestmentManager, Tranche } from "../src/InvestmentManager.sol"; -import { Gateway } from "../src/Gateway.sol"; -import { Escrow } from "../src/Escrow.sol"; -import { LiquidityPoolFactory, MemberlistFactory } from "../src/liquidityPool/Factory.sol"; -import { LiquidityPool } from "../src/liquidityPool/LiquidityPool.sol"; -import { ERC20 } from "../src/token/erc20.sol"; - -import { MemberlistLike, Memberlist } from "../src/token/memberlist.sol"; -import { MockHomeLiquidityPools } from "./mock/MockHomeLiquidityPools.sol"; -import { MockXcmRouter } from "./mock/MockXcmRouter.sol"; -import { Messages } from "../src/Messages.sol"; -import { PauseAdmin } from "../src/admin/PauseAdmin.sol"; -import { DelayedAdmin } from "../src/admin/DelayedAdmin.sol"; +import {InvestmentManager, Tranche} from "../src/InvestmentManager.sol"; +import {Gateway} from "../src/Gateway.sol"; +import {Escrow} from "../src/Escrow.sol"; +import {LiquidityPoolFactory, MemberlistFactory} from "../src/liquidityPool/Factory.sol"; +import {LiquidityPool} from "../src/liquidityPool/LiquidityPool.sol"; +import {ERC20} from "../src/token/erc20.sol"; + +import {MemberlistLike, Memberlist} from "../src/token/memberlist.sol"; +import {MockHomeLiquidityPools} from "./mock/MockHomeLiquidityPools.sol"; +import {MockXcmRouter} from "./mock/MockXcmRouter.sol"; +import {Messages} from "../src/Messages.sol"; +import {PauseAdmin} from "../src/admin/PauseAdmin.sol"; +import {DelayedAdmin} from "../src/admin/DelayedAdmin.sol"; import "forge-std/Test.sol"; import "../src/InvestmentManager.sol"; @@ -24,7 +24,7 @@ interface EscrowLike_ { } interface AuthLike { - function wards(address user) external returns (uint); + function wards(address user) external returns (uint256); } contract InvestmentManagerTest is Test { @@ -50,8 +50,7 @@ contract InvestmentManagerTest is Test { PauseAdmin pauseAdmin = new PauseAdmin(); DelayedAdmin delayedAdmin = new DelayedAdmin(); - gateway = - new Gateway(address(evmInvestmentManager), address(mockXcmRouter), shortWait, longWait, gracePeriod); + gateway = new Gateway(address(evmInvestmentManager), address(mockXcmRouter), shortWait, longWait, gracePeriod); gateway.rely(address(pauseAdmin)); gateway.rely(address(delayedAdmin)); pauseAdmin.file("gateway", address(gateway)); @@ -67,8 +66,7 @@ contract InvestmentManagerTest is Test { // gateway.pause(); // vm.expectRevert(bytes("InvestmentManager/connector-deactivated")); // evmInvestmentManager.processDeposit(address(0), address(0), 0); - // } - + // } function testAddCurrencyWorks(uint128 currency, uint128 badCurrency) public { vm.assume(currency > 0); @@ -77,19 +75,19 @@ contract InvestmentManagerTest is Test { ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); homePools.addCurrency(currency, address(erc20)); - (address address_) = evmInvestmentManager.currencyIdToAddress(currency); + (address address_) = evmInvestmentManager.currencyIdToAddress(currency); assertEq(address_, address(erc20)); // Verify we can't override the same currency id another address ERC20 badErc20 = newErc20("BadActor's Dollar", "BADUSD", 66); vm.expectRevert(bytes("InvestmentManager/currency-id-in-use")); homePools.addCurrency(currency, address(badErc20)); - assertEq( evmInvestmentManager.currencyIdToAddress(currency), address(erc20)); + assertEq(evmInvestmentManager.currencyIdToAddress(currency), address(erc20)); // Verify we can't add a currency address that already exists associated with a different currency id vm.expectRevert(bytes("InvestmentManager/currency-address-in-use")); homePools.addCurrency(badCurrency, address(erc20)); - assertEq( evmInvestmentManager.currencyIdToAddress(currency), address(erc20)); + assertEq(evmInvestmentManager.currencyIdToAddress(currency), address(erc20)); } function testAddPoolWorks(uint64 poolId) public { @@ -148,16 +146,15 @@ contract InvestmentManagerTest is Test { string memory tokenSymbol_ ) = evmInvestmentManager.tranches(poolId, trancheId); - address[] memory liquidityPools_ = evmInvestmentManager.getLiquidityPoolsForTranche(poolId, trancheId); assertEq(poolId, poolId_); assertEq(trancheId, trancheId_); assertEq(block.timestamp, createdAt_); - assertEq( bytes32ToString(stringToBytes32(tokenName)), bytes32ToString(stringToBytes32(tokenName_))); - assertEq( bytes32ToString(stringToBytes32(tokenSymbol)), bytes32ToString(stringToBytes32(tokenSymbol_))); + assertEq(bytes32ToString(stringToBytes32(tokenName)), bytes32ToString(stringToBytes32(tokenName_))); + assertEq(bytes32ToString(stringToBytes32(tokenSymbol)), bytes32ToString(stringToBytes32(tokenSymbol_))); assertEq(decimals, decimals_); - assertEq(liquidityPools_.length, 0); + assertEq(liquidityPools_.length, 0); } function testAddingTrancheMultipleTimesFails( @@ -189,10 +186,7 @@ contract InvestmentManagerTest is Test { for (uint256 i = 0; i < trancheIds.length; i++) { homePools.addTranche(poolId, trancheIds[i], tokenName, tokenSymbol, decimals, price); - ( - uint64 poolId_, - bytes16 trancheId_,,,, - ) = evmInvestmentManager.tranches(poolId, trancheIds[i]); + (uint64 poolId_, bytes16 trancheId_,,,,) = evmInvestmentManager.tranches(poolId, trancheIds[i]); assertEq(poolId, poolId_); assertEq(trancheIds[i], trancheId_); @@ -232,23 +226,23 @@ contract InvestmentManagerTest is Test { bytes16 trancheId, uint128 price, uint128 currency - ) public { + ) public { vm.assume(currency > 0); ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); - homePools.addPool(poolId); // add pool + homePools.addPool(poolId); // add pool homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche - + homePools.addCurrency(currency, address(erc20)); homePools.allowPoolCurrency(poolId, currency); - - address lPoolAddress = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); - address lPool_ = evmInvestmentManager.liquidityPools(poolId, trancheId, address(erc20)); // make sure the pool was stored in connectors + + address lPoolAddress = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); + address lPool_ = evmInvestmentManager.liquidityPools(poolId, trancheId, address(erc20)); // make sure the pool was stored in connectors address[] memory liquidityPools = evmInvestmentManager.getLiquidityPoolsForTranche(poolId, trancheId); // make sure the pool was added to the tranche struct assertEq(lPoolAddress, lPool_); bool lPoolIncluded; - for (uint i=0; i 0); vm.assume(poolId != wrongPoolId); ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); - homePools.addPool(poolId); // add pool + homePools.addPool(poolId); // add pool homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche - + homePools.addCurrency(currency, address(erc20)); homePools.allowPoolCurrency(poolId, currency); vm.expectRevert(bytes("InvestmentManager/pool-does-not-exist")); @@ -328,15 +322,15 @@ contract InvestmentManagerTest is Test { bytes16 trancheId, uint128 price, uint128 currency - ) public { + ) public { vm.assume(currency > 0); ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); - homePools.addPool(poolId); // add pool + homePools.addPool(poolId); // add pool homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche - + homePools.addCurrency(currency, address(erc20)); - + vm.expectRevert(bytes("InvestmentManager/pool-currency-not-allowed")); evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); } @@ -349,41 +343,52 @@ contract InvestmentManagerTest is Test { bytes16 trancheId, uint128 price, uint128 currency - ) public { + ) public { vm.assume(currency > 0); ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); - homePools.addPool(poolId); // add pool + homePools.addPool(poolId); // add pool homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche - + homePools.addCurrency(currency, address(erc20)); homePools.allowPoolCurrency(poolId, currency); - - evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); + + evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); vm.expectRevert(bytes("InvestmentManager/liquidityPool-already-deployed")); - evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); - + evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); } - function testUpdatingMemberWorks(uint64 poolId, uint8 decimals, uint128 currency, string memory tokenName, string memory tokenSymbol, bytes16 trancheId, address user, uint64 validUntil, uint128 price) - public - { + function testUpdatingMemberWorks( + uint64 poolId, + uint8 decimals, + uint128 currency, + string memory tokenName, + string memory tokenSymbol, + bytes16 trancheId, + address user, + uint64 validUntil, + uint128 price + ) public { vm.assume(validUntil >= block.timestamp); vm.assume(user != address(0)); vm.assume(currency > 0); ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); - homePools.addPool(poolId); // add pool + homePools.addPool(poolId); // add pool homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche homePools.addCurrency(currency, address(erc20)); homePools.allowPoolCurrency(poolId, currency); - address lPool_ = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); + address lPool_ = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); homePools.updateMember(poolId, trancheId, user, validUntil); assertTrue(LiquidityPool(lPool_).hasMember(user)); } - - function testUpdatingMemberAsNonRouterFails(uint64 poolId, uint128 currency, bytes16 trancheId, address user, uint64 validUntil) - public - { + + function testUpdatingMemberAsNonRouterFails( + uint64 poolId, + uint128 currency, + bytes16 trancheId, + address user, + uint64 validUntil + ) public { vm.assume(validUntil >= block.timestamp); vm.assume(user != address(0)); vm.assume(currency > 0); @@ -417,29 +422,45 @@ contract InvestmentManagerTest is Test { homePools.updateMember(poolId, trancheId, user, validUntil); } - function testUpdatingTokenPriceWorks(uint64 poolId, uint8 decimals, uint128 currency, string memory tokenName, string memory tokenSymbol, bytes16 trancheId, uint128 price) public { + function testUpdatingTokenPriceWorks( + uint64 poolId, + uint8 decimals, + uint128 currency, + string memory tokenName, + string memory tokenSymbol, + bytes16 trancheId, + uint128 price + ) public { vm.assume(currency > 0); ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); - homePools.addPool(poolId); // add pool + homePools.addPool(poolId); // add pool homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche homePools.addCurrency(currency, address(erc20)); homePools.allowPoolCurrency(poolId, currency); - address lPool_ = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); - + address lPool_ = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); + homePools.updateTokenPrice(poolId, trancheId, price); assertEq(LiquidityPool(lPool_).latestPrice(), price); assertEq(LiquidityPool(lPool_).lastPriceUpdate(), block.timestamp); } - function testUpdatingTokenPriceAsNonRouterFails(uint64 poolId, uint8 decimals, uint128 currency, string memory tokenName, string memory tokenSymbol, bytes16 trancheId, uint128 price) public { + function testUpdatingTokenPriceAsNonRouterFails( + uint64 poolId, + uint8 decimals, + uint128 currency, + string memory tokenName, + string memory tokenSymbol, + bytes16 trancheId, + uint128 price + ) public { vm.assume(currency > 0); ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); - homePools.addPool(poolId); // add pool + homePools.addPool(poolId); // add pool homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche homePools.addCurrency(currency, address(erc20)); homePools.allowPoolCurrency(poolId, currency); - evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); - + evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); + vm.expectRevert(bytes("InvestmentManager/not-the-gateway")); evmInvestmentManager.updateTokenPrice(poolId, trancheId, price); } @@ -542,7 +563,7 @@ contract InvestmentManagerTest is Test { assertEq(erc20.balanceOf(address(this)), initialBalance - amount); assertEq(erc20.balanceOf(address(evmInvestmentManager.escrow())), amount); } - + // function testTransferTrancheTokensToCentrifuge( // uint64 validUntil, // bytes32 centChainAddress, @@ -553,11 +574,11 @@ contract InvestmentManagerTest is Test { // string memory tokenSymbol, // bytes16 trancheId, // uint128 currency - // ) public { + // ) public { // vm.assume(currency > 0); // vm.assume(validUntil > block.timestamp + 7 days); - // address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, currency); + // address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, currency); // homePools.updateMember(poolId, trancheId, address(this), validUntil); // // fund this account with amount @@ -599,9 +620,9 @@ contract InvestmentManagerTest is Test { // vm.assume(validUntil >= block.timestamp); // vm.assume(destinationAddress != address(0)); // vm.assume(currency > 0); - - // address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, currency); - + + // address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, currency); + // homePools.updateMember(poolId, trancheId, destinationAddress, validUntil); // assertTrue(LiquidityPool(lPool_).hasMember(destinationAddress)); // homePools.incomingTransferTrancheTokens(poolId, trancheId, uint64(block.chainid), currency, destinationAddress, amount); @@ -620,7 +641,7 @@ contract InvestmentManagerTest is Test { // ) public { // vm.assume(destinationAddress != address(0)); // vm.assume(currency > 0); - + // deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, currency); // vm.expectRevert(bytes("InvestmentManager/not-a-member")); @@ -635,7 +656,7 @@ contract InvestmentManagerTest is Test { // uint8 decimals, // uint64 validUntil, // address destinationAddress, - // uint128 amount, + // uint128 amount, // uint128 currency // ) public { // vm.assume(validUntil > block.timestamp + 7 days); @@ -663,7 +684,6 @@ contract InvestmentManagerTest is Test { // assertEq(LiquidityPool(lPool_).balanceOf(address(this)), 0); // } - // helpers function deployLiquidityPool( uint64 poolId, @@ -671,15 +691,16 @@ contract InvestmentManagerTest is Test { string memory tokenName, string memory tokenSymbol, bytes16 trancheId, - uint128 currency) internal returns (address lPool) { + uint128 currency + ) internal returns (address lPool) { // deploy liquidityPool ERC20 erc20 = newErc20("X's Dollar", "USDX", 42); - homePools.addPool(poolId); // add pool + homePools.addPool(poolId); // add pool homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, 0); // add tranche homePools.addCurrency(currency, address(erc20)); homePools.allowPoolCurrency(poolId, currency); - - lPool = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); + + lPool = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); } function newErc20(string memory name, string memory symbol, uint8 decimals) internal returns (ERC20) { @@ -739,4 +760,4 @@ contract InvestmentManagerTest is Test { } return false; } -} \ No newline at end of file +} diff --git a/test/LiquidityPool.t.sol b/test/LiquidityPool.t.sol index 2c6d9a1a..c9ef3885 100644 --- a/test/LiquidityPool.t.sol +++ b/test/LiquidityPool.t.sol @@ -2,19 +2,19 @@ pragma solidity ^0.8.18; pragma abicoder v2; -import { InvestmentManager, Tranche } from "../src/InvestmentManager.sol"; -import { Gateway } from "../src/Gateway.sol"; -import { Escrow } from "../src/Escrow.sol"; -import { LiquidityPoolFactory, MemberlistFactory } from "../src/liquidityPool/Factory.sol"; -import { LiquidityPool } from "../src/liquidityPool/LiquidityPool.sol"; -import { ERC20 } from "../src/token/erc20.sol"; - -import { MemberlistLike, Memberlist } from "../src/token/memberlist.sol"; -import { MockHomeLiquidityPools } from "./mock/MockHomeLiquidityPools.sol"; -import { MockXcmRouter } from "./mock/MockXcmRouter.sol"; -import { Messages } from "../src/Messages.sol"; -import { PauseAdmin } from "../src/admin/PauseAdmin.sol"; -import { DelayedAdmin } from "../src/admin/DelayedAdmin.sol"; +import {InvestmentManager, Tranche} from "../src/InvestmentManager.sol"; +import {Gateway} from "../src/Gateway.sol"; +import {Escrow} from "../src/Escrow.sol"; +import {LiquidityPoolFactory, MemberlistFactory} from "../src/liquidityPool/Factory.sol"; +import {LiquidityPool} from "../src/liquidityPool/LiquidityPool.sol"; +import {ERC20} from "../src/token/erc20.sol"; + +import {MemberlistLike, Memberlist} from "../src/token/memberlist.sol"; +import {MockHomeLiquidityPools} from "./mock/MockHomeLiquidityPools.sol"; +import {MockXcmRouter} from "./mock/MockXcmRouter.sol"; +import {Messages} from "../src/Messages.sol"; +import {PauseAdmin} from "../src/admin/PauseAdmin.sol"; +import {DelayedAdmin} from "../src/admin/DelayedAdmin.sol"; import "forge-std/Test.sol"; import "../src/InvestmentManager.sol"; @@ -24,11 +24,10 @@ interface EscrowLike_ { } interface AuthLike { - function wards(address user) external returns (uint); + function wards(address user) external returns (uint256); } contract LiquidityPoolTest is Test { - uint128 constant MAX_UINT128 = type(uint128).max; InvestmentManager evmInvestmentManager; @@ -38,7 +37,6 @@ contract LiquidityPoolTest is Test { Escrow escrow; ERC20 erc20; - function setUp() public { vm.chainId(1); uint256 shortWait = 24 hours; @@ -57,8 +55,7 @@ contract LiquidityPoolTest is Test { PauseAdmin pauseAdmin = new PauseAdmin(); DelayedAdmin delayedAdmin = new DelayedAdmin(); - gateway = - new Gateway(address(evmInvestmentManager), address(mockXcmRouter), shortWait, longWait, gracePeriod); + gateway = new Gateway(address(evmInvestmentManager), address(mockXcmRouter), shortWait, longWait, gracePeriod); gateway.rely(address(pauseAdmin)); gateway.rely(address(delayedAdmin)); pauseAdmin.file("gateway", address(gateway)); @@ -70,7 +67,7 @@ contract LiquidityPoolTest is Test { escrow.rely(address(gateway)); } - function testDepositMint( + function testDepositMint( uint64 poolId, uint8 decimals, string memory tokenName, @@ -80,62 +77,65 @@ contract LiquidityPoolTest is Test { uint128 currencyId, uint256 amount, uint64 validUntil - ) public { - vm.assume(currencyId > 0); - vm.assume(amount < MAX_UINT128); - vm.assume(amount > 1); - vm.assume(validUntil >= block.timestamp); - price = 2; - - address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currencyId, address(erc20)); - LiquidityPool lPool = LiquidityPool(lPool_); - - erc20.mint(address(this), amount); - - // will fail - user not member: can not receive trancheToken - vm.expectRevert(bytes("InvestmentManager/not-a-member")); - lPool.requestDeposit(amount); - homePools.updateMember(poolId, trancheId, address(this), validUntil); // add user as member - - // will fail - user did not give currency allowance to investmentManager - vm.expectRevert(bytes("ERC20/insufficient-allowance")); - lPool.requestDeposit(amount); - erc20.approve(address(evmInvestmentManager), amount); // add allowance - - lPool.requestDeposit(amount); - - // ensure funds are locked in escrow - assertEq(erc20.balanceOf(address(escrow)), amount); - assertEq(erc20.balanceOf(address(this)), 0); - - // trigger executed collectInvest - uint128 _currencyId = evmInvestmentManager.currencyAddressToId(address(erc20)); // retrieve currencyId - uint128 trancheTokensPayout = uint128(amount) / price; // trancheTokenPrice = 2$ - homePools.isExecutedCollectInvest(poolId, trancheId, bytes32(bytes20(address(this))), _currencyId, uint128(amount), trancheTokensPayout); - - // assert deposit & mint values adjusted - assertEq(lPool.maxMint(address(this)), trancheTokensPayout); // max deposit - assertEq(lPool.maxDeposit(address(this)), amount); // max deposit - // assert tranche tokens minted - assertEq(lPool.balanceOf(address(escrow)), trancheTokensPayout); - - // deposit a share of the amount - uint share = 2; - lPool.deposit(amount/share, address(this)); // mint hald the amount - assertEq(lPool.balanceOf(address(this)), trancheTokensPayout/share); - assertEq(lPool.balanceOf(address(escrow)), trancheTokensPayout - trancheTokensPayout/share); - assertEq(lPool.maxMint(address(this)), trancheTokensPayout - trancheTokensPayout/share); // max deposit - assertEq(lPool.maxDeposit(address(this)), amount - amount/share); // max deposit - - // mint the rest - lPool.mint(lPool.maxMint(address(this)), address(this)); - assertEq(lPool.balanceOf(address(this)), trancheTokensPayout - lPool.maxMint(address(this))); - assertTrue(lPool.balanceOf(address(escrow)) <= 1); - assertTrue(lPool.maxMint(address(this)) <= 1 ); - // assertTrue(lPool.maxDeposit(address(this)) <= 2); // todo: fix rounding + ) public { + vm.assume(currencyId > 0); + vm.assume(amount < MAX_UINT128); + vm.assume(amount > 1); + vm.assume(validUntil >= block.timestamp); + price = 2; + + address lPool_ = + deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currencyId, address(erc20)); + LiquidityPool lPool = LiquidityPool(lPool_); + + erc20.mint(address(this), amount); + + // will fail - user not member: can not receive trancheToken + vm.expectRevert(bytes("InvestmentManager/not-a-member")); + lPool.requestDeposit(amount); + homePools.updateMember(poolId, trancheId, address(this), validUntil); // add user as member + + // will fail - user did not give currency allowance to investmentManager + vm.expectRevert(bytes("ERC20/insufficient-allowance")); + lPool.requestDeposit(amount); + erc20.approve(address(evmInvestmentManager), amount); // add allowance + + lPool.requestDeposit(amount); + + // ensure funds are locked in escrow + assertEq(erc20.balanceOf(address(escrow)), amount); + assertEq(erc20.balanceOf(address(this)), 0); + + // trigger executed collectInvest + uint128 _currencyId = evmInvestmentManager.currencyAddressToId(address(erc20)); // retrieve currencyId + uint128 trancheTokensPayout = uint128(amount) / price; // trancheTokenPrice = 2$ + homePools.isExecutedCollectInvest( + poolId, trancheId, bytes32(bytes20(address(this))), _currencyId, uint128(amount), trancheTokensPayout + ); + + // assert deposit & mint values adjusted + assertEq(lPool.maxMint(address(this)), trancheTokensPayout); // max deposit + assertEq(lPool.maxDeposit(address(this)), amount); // max deposit + // assert tranche tokens minted + assertEq(lPool.balanceOf(address(escrow)), trancheTokensPayout); + + // deposit a share of the amount + uint256 share = 2; + lPool.deposit(amount / share, address(this)); // mint hald the amount + assertEq(lPool.balanceOf(address(this)), trancheTokensPayout / share); + assertEq(lPool.balanceOf(address(escrow)), trancheTokensPayout - trancheTokensPayout / share); + assertEq(lPool.maxMint(address(this)), trancheTokensPayout - trancheTokensPayout / share); // max deposit + assertEq(lPool.maxDeposit(address(this)), amount - amount / share); // max deposit + + // mint the rest + lPool.mint(lPool.maxMint(address(this)), address(this)); + assertEq(lPool.balanceOf(address(this)), trancheTokensPayout - lPool.maxMint(address(this))); + assertTrue(lPool.balanceOf(address(escrow)) <= 1); + assertTrue(lPool.maxMint(address(this)) <= 1); + // assertTrue(lPool.maxDeposit(address(this)) <= 2); // todo: fix rounding } - function testRedeem( + function testRedeem( uint64 poolId, uint8 decimals, string memory tokenName, @@ -145,49 +145,52 @@ contract LiquidityPoolTest is Test { uint128 currencyId, uint256 amount, uint64 validUntil - ) public { - vm.assume(currencyId > 0); - vm.assume(amount < MAX_UINT128); - vm.assume(amount > 1); - vm.assume(validUntil >= block.timestamp); - price = 1; - - address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currencyId, address(erc20)); - deposit(lPool_, poolId, trancheId, amount, validUntil); // deposit funds first - LiquidityPool lPool = LiquidityPool(lPool_); - - // will fail - user did not give tranche token allowance to investmentManager - vm.expectRevert(bytes("InvestmentManager/insufficient-balance")); - lPool.requestDeposit(amount); - lPool.approve(address(evmInvestmentManager), amount); // add allowance - - lPool.requestRedeem(amount); - assertEq(lPool.balanceOf(address(escrow)), amount); - - // trigger executed collectRedeem - uint128 _currencyId = evmInvestmentManager.currencyAddressToId(address(erc20)); // retrieve currencyId - uint128 currencyPayout = uint128(amount) / price; - homePools.isExecutedCollectRedeem(poolId, trancheId, bytes32(bytes20(address(this))), _currencyId, currencyPayout, uint128(amount)); - - // assert withdraw & redeem values adjusted - assertEq(lPool.maxWithdraw(address(this)), currencyPayout); // max deposit - assertEq(lPool.maxRedeem(address(this)), amount); // max deposit - assertEq(lPool.balanceOf(address(escrow)), 0); - - console.logUint(lPool.maxRedeem(address(this))); - console.logUint(amount); - - lPool.redeem(amount, address(this), address(this)); // mint hald the amount - assertEq(lPool.balanceOf(address(this)), 0); - assertEq(lPool.balanceOf(address(escrow)), 0); - assertEq(erc20.balanceOf(address(this)), amount); - assertEq(lPool.maxMint(address(this)), 0); - assertEq(lPool.maxDeposit(address(this)),0); - } - - // helpers - - function testWithdraw( + ) public { + vm.assume(currencyId > 0); + vm.assume(amount < MAX_UINT128); + vm.assume(amount > 1); + vm.assume(validUntil >= block.timestamp); + price = 1; + + address lPool_ = + deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currencyId, address(erc20)); + deposit(lPool_, poolId, trancheId, amount, validUntil); // deposit funds first + LiquidityPool lPool = LiquidityPool(lPool_); + + // will fail - user did not give tranche token allowance to investmentManager + vm.expectRevert(bytes("InvestmentManager/insufficient-balance")); + lPool.requestDeposit(amount); + lPool.approve(address(evmInvestmentManager), amount); // add allowance + + lPool.requestRedeem(amount); + assertEq(lPool.balanceOf(address(escrow)), amount); + + // trigger executed collectRedeem + uint128 _currencyId = evmInvestmentManager.currencyAddressToId(address(erc20)); // retrieve currencyId + uint128 currencyPayout = uint128(amount) / price; + homePools.isExecutedCollectRedeem( + poolId, trancheId, bytes32(bytes20(address(this))), _currencyId, currencyPayout, uint128(amount) + ); + + // assert withdraw & redeem values adjusted + assertEq(lPool.maxWithdraw(address(this)), currencyPayout); // max deposit + assertEq(lPool.maxRedeem(address(this)), amount); // max deposit + assertEq(lPool.balanceOf(address(escrow)), 0); + + console.logUint(lPool.maxRedeem(address(this))); + console.logUint(amount); + + lPool.redeem(amount, address(this), address(this)); // mint hald the amount + assertEq(lPool.balanceOf(address(this)), 0); + assertEq(lPool.balanceOf(address(escrow)), 0); + assertEq(erc20.balanceOf(address(this)), amount); + assertEq(lPool.maxMint(address(this)), 0); + assertEq(lPool.maxDeposit(address(this)), 0); + } + + // helpers + + function testWithdraw( uint64 poolId, uint8 decimals, string memory tokenName, @@ -197,44 +200,47 @@ contract LiquidityPoolTest is Test { uint128 currencyId, uint256 amount, uint64 validUntil - ) public { - vm.assume(currencyId > 0); - vm.assume(amount < MAX_UINT128); - vm.assume(amount > 1); - vm.assume(validUntil >= block.timestamp); - price = 1; - - address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currencyId, address(erc20)); - deposit(lPool_, poolId, trancheId, amount, validUntil); // deposit funds first - LiquidityPool lPool = LiquidityPool(lPool_); - - // will fail - user did not give tranche token allowance to investmentManager - vm.expectRevert(bytes("InvestmentManager/insufficient-balance")); - lPool.requestDeposit(amount); - lPool.approve(address(evmInvestmentManager), amount); // add allowance - - lPool.requestRedeem(amount); - assertEq(lPool.balanceOf(address(escrow)), amount); - - // trigger executed collectRedeem - uint128 _currencyId = evmInvestmentManager.currencyAddressToId(address(erc20)); // retrieve currencyId - uint128 currencyPayout = uint128(amount) / price; - homePools.isExecutedCollectRedeem(poolId, trancheId, bytes32(bytes20(address(this))), _currencyId, currencyPayout, uint128(amount)); - - // assert withdraw & redeem values adjusted - assertEq(lPool.maxWithdraw(address(this)), currencyPayout); // max deposit - assertEq(lPool.maxRedeem(address(this)), amount); // max deposit - assertEq(lPool.balanceOf(address(escrow)), 0); - - console.logUint(lPool.maxRedeem(address(this))); - console.logUint(amount); - - lPool.withdraw(amount, address(this), address(this)); // mint hald the amount - assertEq(lPool.balanceOf(address(this)), 0); - assertEq(lPool.balanceOf(address(escrow)), 0); - assertEq(erc20.balanceOf(address(this)), amount); - assertEq(lPool.maxMint(address(this)), 0); - assertEq(lPool.maxDeposit(address(this)),0); + ) public { + vm.assume(currencyId > 0); + vm.assume(amount < MAX_UINT128); + vm.assume(amount > 1); + vm.assume(validUntil >= block.timestamp); + price = 1; + + address lPool_ = + deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currencyId, address(erc20)); + deposit(lPool_, poolId, trancheId, amount, validUntil); // deposit funds first + LiquidityPool lPool = LiquidityPool(lPool_); + + // will fail - user did not give tranche token allowance to investmentManager + vm.expectRevert(bytes("InvestmentManager/insufficient-balance")); + lPool.requestDeposit(amount); + lPool.approve(address(evmInvestmentManager), amount); // add allowance + + lPool.requestRedeem(amount); + assertEq(lPool.balanceOf(address(escrow)), amount); + + // trigger executed collectRedeem + uint128 _currencyId = evmInvestmentManager.currencyAddressToId(address(erc20)); // retrieve currencyId + uint128 currencyPayout = uint128(amount) / price; + homePools.isExecutedCollectRedeem( + poolId, trancheId, bytes32(bytes20(address(this))), _currencyId, currencyPayout, uint128(amount) + ); + + // assert withdraw & redeem values adjusted + assertEq(lPool.maxWithdraw(address(this)), currencyPayout); // max deposit + assertEq(lPool.maxRedeem(address(this)), amount); // max deposit + assertEq(lPool.balanceOf(address(escrow)), 0); + + console.logUint(lPool.maxRedeem(address(this))); + console.logUint(amount); + + lPool.withdraw(amount, address(this), address(this)); // mint hald the amount + assertEq(lPool.balanceOf(address(this)), 0); + assertEq(lPool.balanceOf(address(escrow)), 0); + assertEq(erc20.balanceOf(address(this)), amount); + assertEq(lPool.maxMint(address(this)), 0); + assertEq(lPool.maxDeposit(address(this)), 0); } function testCollectInvest( @@ -253,17 +259,17 @@ contract LiquidityPoolTest is Test { vm.assume(decimals > 0); vm.assume(validUntil > block.timestamp + 7 days); - address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currency, address(erc20)); + address lPool_ = + deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currency, address(erc20)); LiquidityPool lPool = LiquidityPool(lPool_); - + vm.expectRevert(bytes("InvestmentManager/not-a-member")); lPool.collectInvest(address(this)); - + homePools.updateMember(poolId, trancheId, address(this), validUntil); lPool.collectInvest(address(this)); } - function testCollectRedeem( uint64 poolId, bytes16 trancheId, @@ -281,7 +287,8 @@ contract LiquidityPoolTest is Test { vm.assume(trancheDecimals > 0); vm.assume(validUntil > block.timestamp + 7 days); - address lPool_ = deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currency, address(erc20)); + address lPool_ = + deployLiquidityPool(poolId, decimals, tokenName, tokenSymbol, trancheId, price, currency, address(erc20)); LiquidityPool lPool = LiquidityPool(lPool_); homePools.allowPoolCurrency(poolId, currency); @@ -292,13 +299,7 @@ contract LiquidityPoolTest is Test { lPool.collectRedeem(address(this)); } - function deposit( - address _lPool, - uint64 poolId, - bytes16 trancheId, - uint256 amount, - uint64 validUntil) - public { + function deposit(address _lPool, uint64 poolId, bytes16 trancheId, uint256 amount, uint64 validUntil) public { LiquidityPool lPool = LiquidityPool(_lPool); erc20.mint(address(this), amount); homePools.updateMember(poolId, trancheId, address(this), validUntil); // add user as member @@ -306,7 +307,9 @@ contract LiquidityPoolTest is Test { lPool.requestDeposit(amount); // trigger executed collectInvest uint128 currencyId = evmInvestmentManager.currencyAddressToId(address(erc20)); // retrieve currencyId - homePools.isExecutedCollectInvest(poolId, trancheId, bytes32(bytes20(address(this))), currencyId, uint128(amount), uint128(amount)); + homePools.isExecutedCollectInvest( + poolId, trancheId, bytes32(bytes20(address(this))), currencyId, uint128(amount), uint128(amount) + ); lPool.deposit(amount, address(this)); // withdraw hald the amount } @@ -320,12 +323,12 @@ contract LiquidityPoolTest is Test { uint128 currency, address erc20 ) public returns (address) { - homePools.addPool(poolId); // add pool - homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche + homePools.addPool(poolId); // add pool + homePools.addTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); // add tranche homePools.addCurrency(currency, address(erc20)); homePools.allowPoolCurrency(poolId, currency); - - address lPoolAddress = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); + + address lPoolAddress = evmInvestmentManager.deployLiquidityPool(poolId, trancheId, address(erc20)); return lPoolAddress; } @@ -335,6 +338,4 @@ contract LiquidityPoolTest is Test { erc20.file("symbol", symbol); return erc20; } - - -} \ No newline at end of file +} diff --git a/test/Messages.t.sol b/test/Messages.t.sol index d6efc128..23c332ee 100644 --- a/test/Messages.t.sol +++ b/test/Messages.t.sol @@ -20,8 +20,7 @@ contract MessagesTest is Test { assertEq(Messages.formatAddCurrency(currency, currencyAddress), expectedHex); - (uint128 decodedCurrency, address decodedCurrencyAddress) = - Messages.parseAddCurrency(expectedHex.ref(0)); + (uint128 decodedCurrency, address decodedCurrencyAddress) = Messages.parseAddCurrency(expectedHex.ref(0)); assertEq(uint256(decodedCurrency), currency); assertEq(decodedCurrencyAddress, currencyAddress); } @@ -105,8 +104,7 @@ contract MessagesTest is Test { uint8 decimals, uint128 price ) public { - bytes memory _message = - Messages.formatAddTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); + bytes memory _message = Messages.formatAddTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); ( uint64 decodedPoolId, bytes16 decodedTrancheId, @@ -241,8 +239,13 @@ contract MessagesTest is Test { expectedHex ); - (uint64 decodedPoolId, bytes16 decodedTrancheId, uint decodedCurrency, address decodedReceiver, uint128 decodedAmount) = - Messages.parseTransferTrancheTokens20(expectedHex.ref(0)); + ( + uint64 decodedPoolId, + bytes16 decodedTrancheId, + uint256 decodedCurrency, + address decodedReceiver, + uint128 decodedAmount + ) = Messages.parseTransferTrancheTokens20(expectedHex.ref(0)); assertEq(uint256(decodedPoolId), poolId); assertEq(decodedTrancheId, trancheId); assertEq(decodedCurrency, currency); @@ -306,8 +309,13 @@ contract MessagesTest is Test { amount ); - (uint64 decodedPoolId, bytes16 decodedTrancheId, uint128 decodedCurrency, address decodedDestinationAddress, uint256 decodedAmount) = - Messages.parseTransferTrancheTokens20(_message.ref(0)); + ( + uint64 decodedPoolId, + bytes16 decodedTrancheId, + uint128 decodedCurrency, + address decodedDestinationAddress, + uint256 decodedAmount + ) = Messages.parseTransferTrancheTokens20(_message.ref(0)); assertEq(uint256(decodedPoolId), uint256(poolId)); assertEq(decodedTrancheId, trancheId); assertEq(decodedCurrency, currency); @@ -324,9 +332,7 @@ contract MessagesTest is Test { bytes memory expectedHex = hex"090000000000000001811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e4000000"; - assertEq( - Messages.formatIncreaseInvestOrder(poolId, trancheId, investor, currency, amount), expectedHex - ); + assertEq(Messages.formatIncreaseInvestOrder(poolId, trancheId, investor, currency, amount), expectedHex); ( uint64 decodedPoolId, @@ -374,9 +380,7 @@ contract MessagesTest is Test { bytes memory expectedHex = hex"0a0000000000000001811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e4000000"; - assertEq( - Messages.formatDecreaseInvestOrder(poolId, trancheId, investor, currency, amount), expectedHex - ); + assertEq(Messages.formatDecreaseInvestOrder(poolId, trancheId, investor, currency, amount), expectedHex); ( uint64 decodedPoolId, @@ -424,9 +428,7 @@ contract MessagesTest is Test { bytes memory expectedHex = hex"0b0000000000000001811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e4000000"; - assertEq( - Messages.formatIncreaseRedeemOrder(poolId, trancheId, investor, currency, amount), expectedHex - ); + assertEq(Messages.formatIncreaseRedeemOrder(poolId, trancheId, investor, currency, amount), expectedHex); ( uint64 decodedPoolId, @@ -474,9 +476,7 @@ contract MessagesTest is Test { bytes memory expectedHex = hex"0c0000000000000001811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e4000000"; - assertEq( - Messages.formatDecreaseRedeemOrder(poolId, trancheId, investor, currency, amount), expectedHex - ); + assertEq(Messages.formatDecreaseRedeemOrder(poolId, trancheId, investor, currency, amount), expectedHex); ( uint64 decodedPoolId, @@ -519,7 +519,7 @@ contract MessagesTest is Test { uint64 poolId = 1; bytes16 trancheId = bytes16(hex"811acd5b3f17c06841c7e41e9e04cb1b"); bytes32 investor = bytes32(0x4564564564564564564564564564564564564564564564564564564564564564); - uint128 currency = 246803579; + uint128 currency = 246803579; bytes memory expectedHex = hex"0d0000000000000001811acd5b3f17c06841c7e41e9e04cb1b45645645645645645645645645645645645645645645645645645645645645640000000000000000000000000eb5ec7b"; @@ -585,9 +585,7 @@ contract MessagesTest is Test { hex"0f0000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000"; assertEq( - Messages.formatExecutedDecreaseInvestOrder( - poolId, trancheId, investor, currency, currencyPayout - ), + Messages.formatExecutedDecreaseInvestOrder(poolId, trancheId, investor, currency, currencyPayout), expectedHex ); @@ -612,9 +610,8 @@ contract MessagesTest is Test { uint128 currency, uint128 currencyPayout ) public { - bytes memory _message = Messages.formatExecutedDecreaseInvestOrder( - poolId, trancheId, investor, currency, currencyPayout - ); + bytes memory _message = + Messages.formatExecutedDecreaseInvestOrder(poolId, trancheId, investor, currency, currencyPayout); ( uint64 decodedPoolId, bytes16 decodedTrancheId, @@ -636,14 +633,12 @@ contract MessagesTest is Test { bytes32 investor = bytes32(0x1231231231231231231231231231231231231231000000000000000000000000); uint128 currency = 246803579; uint128 currencyPayout = 50000000000000000000000000; - + bytes memory expectedHex = hex"100000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b0000000000295be96e64066972000000"; assertEq( - Messages.formatExecutedDecreaseRedeemOrder( - poolId, trancheId, investor, currency, currencyPayout - ), + Messages.formatExecutedDecreaseRedeemOrder(poolId, trancheId, investor, currency, currencyPayout), expectedHex ); @@ -668,9 +663,8 @@ contract MessagesTest is Test { uint128 currency, uint128 currencyPayout ) public { - bytes memory _message = Messages.formatExecutedDecreaseRedeemOrder( - poolId, trancheId, investor, currency, currencyPayout - ); + bytes memory _message = + Messages.formatExecutedDecreaseRedeemOrder(poolId, trancheId, investor, currency, currencyPayout); ( uint64 decodedPoolId, bytes16 decodedTrancheId, @@ -687,13 +681,12 @@ contract MessagesTest is Test { } function testExecutedCollectInvest() public { - uint64 poolId = 12378532; + uint64 poolId = 12378532; bytes16 trancheId = bytes16(hex"811acd5b3f17c06841c7e41e9e04cb1b"); bytes32 investor = bytes32(0x1231231231231231231231231231231231231231000000000000000000000000); uint128 currency = 246803579; uint128 currencyPayout = 100000000000000000000000000; uint128 trancheTokensPayout = 50000000000000000000000000; - bytes memory expectedHex = hex"110000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000000000000000eb5ec7b000000000052b7d2dcc80cd2e40000000000000000295be96e64066972000000"; @@ -803,7 +796,7 @@ contract MessagesTest is Test { assertEq(decodedPoolId, poolId); assertEq(decodedTrancheId, trancheId); - + assertEq(decodedInvestor, address(bytes20(investor))); assertEq(decodedCurrency, currency); } @@ -813,8 +806,8 @@ contract MessagesTest is Test { uint128 currencyPayout, uint128 trancheTokensRedeemed ) internal { - (,,,, uint128 decodedCurrencyPayout, uint128 decodedTrancheTokensRedeemed) - = Messages.parseExecutedCollectRedeem(expectedHex.ref(0)); + (,,,, uint128 decodedCurrencyPayout, uint128 decodedTrancheTokensRedeemed) = + Messages.parseExecutedCollectRedeem(expectedHex.ref(0)); assertEq(decodedCurrencyPayout, currencyPayout); assertEq(decodedTrancheTokensRedeemed, trancheTokensRedeemed); diff --git a/test/mock/MockHomeLiquidityPools.sol b/test/mock/MockHomeLiquidityPools.sol index fdab8c0a..29207372 100644 --- a/test/mock/MockHomeLiquidityPools.sol +++ b/test/mock/MockHomeLiquidityPools.sol @@ -57,8 +57,7 @@ contract MockHomeLiquidityPools is Test { uint8 decimals, uint128 price ) public { - bytes memory _message = - Messages.formatAddTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); + bytes memory _message = Messages.formatAddTranche(poolId, trancheId, tokenName, tokenSymbol, decimals, price); router.handle(_message); } @@ -113,7 +112,8 @@ contract MockHomeLiquidityPools is Test { uint128 trancheTokensPayout ) public { bytes memory _message = Messages.formatExecutedCollectInvest( - poolId, trancheId, investor, currency, currencyPayout, trancheTokensPayout); + poolId, trancheId, investor, currency, currencyPayout, trancheTokensPayout + ); router.handle(_message); } @@ -126,10 +126,10 @@ contract MockHomeLiquidityPools is Test { uint128 trancheTokensPayout ) public { bytes memory _message = Messages.formatExecutedCollectRedeem( - poolId, trancheId, investor, currency, currencyPayout, trancheTokensPayout); + poolId, trancheId, investor, currency, currencyPayout, trancheTokensPayout + ); router.handle(_message); - } - + } function dispatch( uint32 _destinationDomain,