Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 75 additions & 16 deletions packages/loopring_v3/contracts/amm/AmplifiedAmmController.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "./IAmmController.sol";
import "../amm/LoopringAmmPool.sol";
Expand All @@ -19,8 +20,14 @@ contract AmplifiedAmmController is IAmmController, Claimable

uint public constant AMPLIFICATION_FACTOR_BASE = (10 ** 18);

uint public constant MIN_CURVE_CHANGE_DELAY = 7 days;
uint public constant CURVE_CHANGE_AUTH_WINDOW = 7 days;

mapping(address => uint) public amplificationFactors;

mapping(address => uint) public curveChangeAuthorization;


function getInitialVirtualBalances(
uint96[] memory joinAmounts
)
Expand All @@ -37,44 +44,96 @@ contract AmplifiedAmmController is IAmmController, Claimable
return vTokenBalancesL2;
}

function getVirtualBalances(
uint96[] memory tokenBalancesL2,
uint96[] memory /*vTokenBalancesL2*/
function authorizeVirtualBalances(
uint96[] memory balances,
uint96[] memory /*vBalancesOld*/,
uint96[] memory vBalancesNew,
bytes memory /*data*/
)
external
view
override
returns (uint96[] memory)
returns (bool)
{
// Only allow updating the virtual balances if the AF = 1
require(getAmplificationFactor(msg.sender) == AMPLIFICATION_FACTOR_BASE, "INVALID_OPERATION");
address pool = msg.sender;

// Just set the virtual balances to the actual balances
uint96[] memory vTokenBalancesL2 = new uint96[](tokenBalancesL2.length);
for (uint i = 0; i < tokenBalancesL2.length; i++) {
vTokenBalancesL2[i] = tokenBalancesL2[i];
// Check if a curve change was explicitly authorized
if (consumeCurveChangeAuthorized(pool)) {
return true;
}
return vTokenBalancesL2;

// Special case: Always allow updating the virtual balances if the AF = 1
if (getAmplificationFactor(pool) == AMPLIFICATION_FACTOR_BASE) {
for (uint i = 0; i < balances.length; i++) {
if(vBalancesNew[i] != balances[i]) {
return false;
}
}
return true;
}

return false;
}

function authorizeCurveChange(address pool)
external
onlyOwner
{
curveChangeAuthorization[pool] = block.timestamp + MIN_CURVE_CHANGE_DELAY;
}

function setAmplificationFactor(
address amm,
address pool,
uint amplificationFactor
)
external
onlyOwner
{
amplificationFactors[amm] = amplificationFactor;
amplificationFactors[pool] = amplificationFactor;
}

function getAmplificationFactor(address amm)
function getAmplificationFactor(address pool)
public
view
returns (uint amplificationFactor)
{
amplificationFactor = amplificationFactors[amm];
amplificationFactor = amplificationFactors[pool];
if (amplificationFactor == 0) {
amplificationFactor = AMPLIFICATION_FACTOR_BASE;
}
}

function setupPool(
LoopringAmmPool pool,
AmmData.PoolConfig calldata config
)
external
onlyOwner
{
pool.setupPool(config);
}

function enterExitMode(
LoopringAmmPool pool,
bool enabled
)
external
onlyOwner
{
pool.enterExitMode(enabled);
}

// == Internal Functions ==

function consumeCurveChangeAuthorized(address pool)
internal
returns (bool)
{
uint timestamp = curveChangeAuthorization[pool];
bool authorized = (timestamp <= block.timestamp) && (block.timestamp <= timestamp + MIN_CURVE_CHANGE_DELAY);

// Remove authorization
delete curveChangeAuthorization[pool];

return authorized;
}
}
19 changes: 11 additions & 8 deletions packages/loopring_v3/contracts/amm/IAmmController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ interface IAmmController

/// @dev Called by the pool contract when a SET_VIRTUAL_BALANCES operation is done
/// on the pool.
/// @param tokenBalancesL2 The balances in the pool
/// @param vTokenBalancesL2 The current virtual balances in the pool
/// @return The new virtual balances in the pool
function getVirtualBalances(
uint96[] memory tokenBalancesL2,
uint96[] memory vTokenBalancesL2
/// @param balances The balances in the pool
/// @param vBalancesOld The current virtual balances in the pool
/// @param vBalancesNew The new virtual balances in the pool
/// @param data Custom data
/// @return True if vBalancesNew can be used, else false
function authorizeVirtualBalances(
uint96[] memory balances,
uint96[] memory vBalancesOld,
uint96[] memory vBalancesNew,
bytes memory data
)
external
view
returns (uint96[] memory);
returns (bool);
}
10 changes: 9 additions & 1 deletion packages/loopring_v3/contracts/amm/LoopringAmmPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ contract LoopringAmmPool is
bool _joinsDisabled
)
{
require(_controller != IAmmController(0), "ZERO_ADDRESS");
controller = _controller;
assetManager = _assetManager;
joinsDisabled = _joinsDisabled;
Expand All @@ -98,9 +99,17 @@ contract LoopringAmmPool is
external
nonReentrant
{
require(state.accountID == 0 || msg.sender == address(controller), "UNAUTHORIZED");
state.setupPool(config);
}

function enterExitMode(bool enabled)
external
onlyFromController
{
state.exitMode = enabled;
}

// Anyone is able to shut down the pool when requests aren't being processed any more.
function shutdown(address exitOwner)
external
Expand All @@ -113,7 +122,6 @@ contract LoopringAmmPool is

function shutdownByController()
external
payable
onlyWhenOnline
nonReentrant
onlyFromController
Expand Down
10 changes: 9 additions & 1 deletion packages/loopring_v3/contracts/amm/libamm/AmmData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ library AmmData
uint32 validUntil;
}

struct PoolVirtualBalances
{
uint96[] vBalancesNew;
bytes data;
}

struct PoolDeposit
{
uint96[] amounts;
Expand All @@ -82,7 +88,8 @@ library AmmData
uint16 tokenID;
}

struct Settings {
struct Settings
{
IAmmController controller;
IAssetManager assetManager;
bool joinsDisabled;
Expand Down Expand Up @@ -142,5 +149,6 @@ library AmmData
mapping (bytes32 => bool) approvedTx;

mapping (address => uint96) balancesL1;
bool exitMode;
}
}
12 changes: 7 additions & 5 deletions packages/loopring_v3/contracts/amm/libamm/AmmDepositProcess.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ library AmmDepositProcess
{
require(poolDeposit.amounts.length == ctx.tokens.length, "INVALID_DEPOSIT_DATA");
for (uint i = 0; i < ctx.tokens.length; i++) {
address token = ctx.tokens[i].addr;
uint96 amount = poolDeposit.amounts[i];
verifyDepositTx(ctx, ctx.tokens[i].tokenID, amount);
S.deposit(token, amount);
S.balancesL1[token] = S.balancesL1[token].sub(amount);
if (amount > 0) {
address token = ctx.tokens[i].addr;
verifyDepositTx(ctx, ctx.tokens[i].tokenID, amount);
S.deposit(token, amount);
S.balancesL1[token] = S.balancesL1[token].sub(amount);
}
}
}

Expand Down Expand Up @@ -68,7 +70,7 @@ library AmmDepositProcess
// tokenID == tokenID &&
packedData & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff == (uint(ExchangeData.TransactionType.DEPOSIT) << 208) | (uint(address(this)) << 48) | (uint(ctx.accountID) << 16) | uint(tokenID) &&
amount == txAmount,
"INVALID_DEPOSIT_TX_DATA"
"INVALID_AMM_DEPOSIT_TX_DATA"
);

ctx.txsDataPtr += ExchangeData.TX_DATA_AVAILABILITY_SIZE;
Expand Down
24 changes: 14 additions & 10 deletions packages/loopring_v3/contracts/amm/libamm/AmmExitProcess.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@ import "../../lib/EIP712.sol";
import "../../lib/ERC20SafeTransfer.sol";
import "../../lib/MathUint.sol";
import "../../lib/MathUint96.sol";
import "../../lib/SignatureUtil.sol";
import "../../lib/TransferUtil.sol";
import "../../thirdparty/SafeCast.sol";
import "./AmmUtil.sol";
import "./AmmData.sol";
import "./AmmExitRequest.sol";
import "./AmmPoolToken.sol";
import "./AmmSignature.sol";
import "./AmmUtil.sol";


/// @title AmmExitProcess
library AmmExitProcess
{
using AmmPoolToken for AmmData.State;
using AmmSignature for bytes32;
using AmmUtil for AmmData.Context;
using AmmUtil for uint96;
using ERC20SafeTransfer for address;
using MathUint for uint;
using MathUint96 for uint96;
using SafeCast for uint;
using SignatureUtil for bytes32;
using TransactionReader for ExchangeData.Block;
using TransferUtil for address;

Expand All @@ -49,14 +49,18 @@ library AmmExitProcess
bool isForcedExit = false;

if (signature.length == 0) {
bytes32 forcedExitHash = AmmExitRequest.hash(ctx.domainSeparator, S.forcedExit[exit.owner]);
if (txHash == forcedExitHash) {
delete S.forcedExit[exit.owner];
S.forcedExitCount--;
isForcedExit = true;
if (S.exitMode) {
require(exit.fee == 0, "INVALID_FEE");
} else {
require(S.approvedTx[txHash], "INVALID_ONCHAIN_APPROVAL");
delete S.approvedTx[txHash];
bytes32 forcedExitHash = AmmExitRequest.hash(ctx.domainSeparator, S.forcedExit[exit.owner]);
if (txHash == forcedExitHash) {
delete S.forcedExit[exit.owner];
S.forcedExitCount--;
isForcedExit = true;
} else {
require(S.approvedTx[txHash], "INVALID_ONCHAIN_APPROVAL");
delete S.approvedTx[txHash];
}
}
} else if (signature.length == 1) {
ctx.verifySignatureL2(exit.owner, txHash, signature);
Expand Down
4 changes: 2 additions & 2 deletions packages/loopring_v3/contracts/amm/libamm/AmmJoinProcess.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ import "../../core/impl/libtransactions/TransferTransaction.sol";
import "../../lib/EIP712.sol";
import "../../lib/MathUint.sol";
import "../../lib/MathUint96.sol";
import "../../lib/SignatureUtil.sol";
import "../../thirdparty/SafeCast.sol";
import "./AmmData.sol";
import "./AmmJoinRequest.sol";
import "./AmmPoolToken.sol";
import "./AmmSignature.sol";
import "./AmmUtil.sol";


/// @title AmmJoinProcess
library AmmJoinProcess
{
using AmmPoolToken for AmmData.State;
using AmmSignature for bytes32;
using AmmUtil for AmmData.State;
using AmmUtil for AmmData.Context;
using AmmUtil for uint96;
using MathUint for uint;
using MathUint96 for uint96;
using SafeCast for uint;
using SignatureUtil for bytes32;
using TransactionReader for ExchangeData.Block;

// event JoinProcessed(address owner, uint96 mintAmount, uint96[] amounts);
Expand Down
2 changes: 1 addition & 1 deletion packages/loopring_v3/contracts/amm/libamm/AmmPoolToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ library AmmPoolToken
uint256 deadline,
bytes calldata signature
)
internal
public
{
require(deadline >= block.timestamp, 'EXPIRED');

Expand Down
25 changes: 25 additions & 0 deletions packages/loopring_v3/contracts/amm/libamm/AmmSignature.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../../lib/SignatureUtil.sol";


/// @title AmmSignature
library AmmSignature
{
using SignatureUtil for bytes32;

function verifySignature(
bytes32 signHash,
address signer,
bytes memory signature
)
public
view
returns (bool)
{
return signHash.verifySignature(signer, signature);
}
}
Loading