Skip to content

Commit

Permalink
Merge branch 'v2.3-fix-review' into prateek/fix-verify-intent
Browse files Browse the repository at this point in the history
  • Loading branch information
EdNoepel committed Oct 7, 2024
2 parents 819439b + 4d7aeb8 commit cf7ae15
Show file tree
Hide file tree
Showing 40 changed files with 716 additions and 229 deletions.
9 changes: 8 additions & 1 deletion packages/perennial-account/contracts/Controller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,17 @@ contract Controller is Factory, IController {
IMarket market = groupToMarkets[owner][group][i];
RebalanceConfig memory marketRebalanceConfig = _rebalanceConfigs[owner][group][address(market)];
(bool canMarketRebalance, Fixed6 imbalance) =
RebalanceLib.checkMarket(marketRebalanceConfig, groupCollateral, actualCollateral[i]);
RebalanceLib.checkMarket(
marketRebalanceConfig,
groupToMaxRebalanceFee[owner][group],
groupCollateral,
actualCollateral[i]
);
imbalances[i] = imbalance;
canRebalance = canRebalance || canMarketRebalance;
}

// if group does not exist or was deleted, arrays will be empty and function will return (0, false, 0)
}

/// @inheritdoc IController
Expand Down
8 changes: 5 additions & 3 deletions packages/perennial-account/contracts/Controller_Arbitrum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ contract Controller_Arbitrum is Controller_Incentivized, Kept_Arbitrum {
/// @dev Creates instance of Controller which compensates keepers
/// @param implementation Pristine collateral account contract
/// @param marketFactory Market Factory contract
/// @param nonceManager Nonce manager contract for relayed messages
constructor(address implementation, IMarketFactory marketFactory, IVerifierBase nonceManager)
Controller_Incentivized(implementation, marketFactory, nonceManager) {}
/// @param nonceManager Verifier contract to which nonce and group cancellations are relayed
constructor(
address implementation, IMarketFactory marketFactory,
IVerifierBase nonceManager
) Controller_Incentivized(implementation, marketFactory, nonceManager) {}

/// @dev Use the Kept_Arbitrum implementation for calculating the dynamic fee
function _calldataFee(
Expand Down
202 changes: 152 additions & 50 deletions packages/perennial-account/contracts/Controller_Incentivized.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,78 +34,115 @@ import { Withdrawal } from "./types/Withdrawal.sol";
abstract contract Controller_Incentivized is Controller, IRelayer, Kept {
/// @dev Handles relayed messages for nonce cancellation
IVerifierBase public immutable nonceManager;

/// @dev Configuration used to calculate keeper compensation
KeepConfig public keepConfig;

/// @dev Configuration used to calculate keeper compensation with buffered gas
KeepConfig public keepConfigBuffered;

/// @dev Configuration used to calculate keeper compensation to withdraw from a collateral account
KeepConfig public keepConfigWithdrawal;

/// @dev Creates instance of Controller which compensates keepers
/// @param implementation_ Pristine collateral account contract
/// @param marketFactory_ Market factory contract
/// @param nonceManager_ Nonce manager contract for relayed messages
constructor(address implementation_, IMarketFactory marketFactory_, IVerifierBase nonceManager_)
Controller(implementation_, marketFactory_) {
/// @param nonceManager_ Verifier contract to which nonce and group cancellations are relayed
constructor(
address implementation_, IMarketFactory marketFactory_,
IVerifierBase nonceManager_
) Controller(implementation_, marketFactory_) {
nonceManager = nonceManager_;
}

/// @notice Configures message verification and keeper compensation
/// @param verifier_ Contract used to validate collateral account message signatures
/// @param chainlinkFeed_ ETH-USD price feed used for calculating keeper compensation
/// @param keepConfig_ Configuration used to compensate keepers
/// @param keepConfig_ Configuration used for unbuffered keeper compensation
/// @param keepConfigBuffered_ Configuration used for buffered keeper compensation
/// @param keepConfigWithdrawal_ Configuration used to compensate keepers for withdrawals
function initialize(
IAccountVerifier verifier_,
AggregatorV3Interface chainlinkFeed_,
KeepConfig memory keepConfig_
KeepConfig memory keepConfig_,
KeepConfig memory keepConfigBuffered_,
KeepConfig memory keepConfigWithdrawal_
) external initializer(1) {
__Factory__initialize();
__Kept__initialize(chainlinkFeed_, DSU);
verifier = verifier_;
keepConfig = keepConfig_;
keepConfigBuffered = keepConfigBuffered_;
keepConfigWithdrawal = keepConfigWithdrawal_;
}

/// @inheritdoc IController
function changeRebalanceConfigWithSignature(
RebalanceConfigChange calldata configChange,
bytes calldata signature
) override external {
)
external
override
keepCollateralAccount(
configChange.action.common.account,
abi.encode(configChange, signature),
configChange.action.maxFee,
0
)
{
_changeRebalanceConfigWithSignature(configChange, signature);
_compensateKeeper(configChange.action);
}

/// @inheritdoc IController
function deployAccountWithSignature(
DeployAccount calldata deployAccount_,
bytes calldata signature
) override external {
IAccount account = _deployAccountWithSignature(deployAccount_, signature);
bytes memory data = abi.encode(address(account), deployAccount_.action.maxFee);
_handleKeeperFee(keepConfig, 0, msg.data[0:0], 0, data);
)
external
override
keepCollateralAccount(
deployAccount_.action.common.account,
abi.encode(deployAccount_, signature),
deployAccount_.action.maxFee,
0
)
{
_deployAccountWithSignature(deployAccount_, signature);
}

/// @inheritdoc IController
function marketTransferWithSignature(
MarketTransfer calldata marketTransfer,
bytes calldata signature
) override external {
)
external
override
keepCollateralAccount(
marketTransfer.action.common.account,
abi.encode(marketTransfer, signature),
marketTransfer.action.maxFee,
1
)
{
IAccount account = IAccount(getAccountAddress(marketTransfer.action.common.account));
bytes memory data = abi.encode(account, marketTransfer.action.maxFee);

// if we're depositing collateral to the market, pay the keeper before transferring funds
if (marketTransfer.amount.gte(Fixed6Lib.ZERO)) {
_handleKeeperFee(keepConfig, 0, msg.data[0:0], 0, data);
_marketTransferWithSignature(account, marketTransfer, signature);
// otherwise handle the keeper fee normally, after withdrawing to the collateral account
} else {
_marketTransferWithSignature(account, marketTransfer, signature);
_handleKeeperFee(keepConfig, 0, msg.data[0:0], 0, data);
}
_marketTransferWithSignature(account, marketTransfer, signature);
}

/// @inheritdoc IController
function rebalanceGroup(address owner, uint256 group) override external {
function rebalanceGroup(
address owner,
uint256 group
)
external
override
keepCollateralAccount(
owner,
abi.encode(owner, group),
groupToMaxRebalanceFee[owner][group],
groupToMarkets[owner][group].length
)
{
_rebalanceGroup(owner, group);
address account = getAccountAddress(owner);
bytes memory data = abi.encode(account, groupToMaxRebalanceFee[owner][group]);
_handleKeeperFee(keepConfig, 0, msg.data[0:0], 0, data);
}

/// @inheritdoc IController
Expand All @@ -116,7 +153,13 @@ abstract contract Controller_Incentivized is Controller, IRelayer, Kept {
address account = getAccountAddress(withdrawal.action.common.account);
// levy fee prior to withdrawal
bytes memory data = abi.encode(account, withdrawal.action.maxFee);
_handleKeeperFee(keepConfig, 0, msg.data[0:0], 0, data);
_handleKeeperFee(
keepConfigWithdrawal,
0, // no way to calculate applicable gas prior to invocation
abi.encode(withdrawal, signature),
0,
data
);
_withdrawWithSignature(IAccount(account), withdrawal, signature);
}

Expand All @@ -125,12 +168,19 @@ abstract contract Controller_Incentivized is Controller, IRelayer, Kept {
RelayedNonceCancellation calldata message,
bytes calldata outerSignature,
bytes calldata innerSignature
) override external {
)
external
override
keepCollateralAccount(
message.action.common.account,
abi.encode(message, outerSignature, innerSignature),
message.action.maxFee,
0
)
{
// ensure the message was signed by the owner or a delegated signer
verifier.verifyRelayedNonceCancellation(message, outerSignature);

_compensateKeeper(message.action);

// relay the message to Verifier
nonceManager.cancelNonceWithSignature(message.nonceCancellation, innerSignature);
}
Expand All @@ -140,12 +190,19 @@ abstract contract Controller_Incentivized is Controller, IRelayer, Kept {
RelayedGroupCancellation calldata message,
bytes calldata outerSignature,
bytes calldata innerSignature
) override external {
)
external
override
keepCollateralAccount(
message.action.common.account,
abi.encode(message, outerSignature, innerSignature),
message.action.maxFee,
0
)
{
// ensure the message was signed by the owner or a delegated signer
verifier.verifyRelayedGroupCancellation(message, outerSignature);

_compensateKeeper(message.action);

// relay the message to Verifier
nonceManager.cancelGroupWithSignature(message.groupCancellation, innerSignature);
}
Expand All @@ -155,12 +212,19 @@ abstract contract Controller_Incentivized is Controller, IRelayer, Kept {
RelayedOperatorUpdate calldata message,
bytes calldata outerSignature,
bytes calldata innerSignature
) override external {
)
external
override
keepCollateralAccount(
message.action.common.account,
abi.encode(message, outerSignature, innerSignature),
message.action.maxFee,
0
)
{
// ensure the message was signed by the owner or a delegated signer
verifier.verifyRelayedOperatorUpdate(message, outerSignature);

_compensateKeeper(message.action);

// relay the message to MarketFactory
marketFactory.updateOperatorWithSignature(message.operatorUpdate, innerSignature);
}
Expand All @@ -170,12 +234,19 @@ abstract contract Controller_Incentivized is Controller, IRelayer, Kept {
RelayedSignerUpdate calldata message,
bytes calldata outerSignature,
bytes calldata innerSignature
) override external {
)
external
override
keepCollateralAccount(
message.action.common.account,
abi.encode(message, outerSignature, innerSignature),
message.action.maxFee,
0
)
{
// ensure the message was signed by the owner or a delegated signer
verifier.verifyRelayedSignerUpdate(message, outerSignature);

_compensateKeeper(message.action);

// relay the message to MarketFactory
marketFactory.updateSignerWithSignature(message.signerUpdate, innerSignature);
}
Expand All @@ -185,21 +256,23 @@ abstract contract Controller_Incentivized is Controller, IRelayer, Kept {
RelayedAccessUpdateBatch calldata message,
bytes calldata outerSignature,
bytes calldata innerSignature
) override external {
)
external
override
keepCollateralAccount(
message.action.common.account,
abi.encode(message, outerSignature, innerSignature),
message.action.maxFee,
0
)
{
// ensure the message was signed by the owner or a delegated signer
verifier.verifyRelayedAccessUpdateBatch(message, outerSignature);

_compensateKeeper(message.action);

// relay the message to MarketFactory
marketFactory.updateAccessBatchWithSignature(message.accessUpdateBatch, innerSignature);
}

function _compensateKeeper(Action calldata action) internal virtual {
bytes memory data = abi.encode(getAccountAddress(action.common.account), action.maxFee);
_handleKeeperFee(keepConfig, 0, msg.data[0:0], 0, data);
}

/// @dev Transfers funds from collateral account to controller, and limits compensation
/// to the user-defined maxFee in the Action message
/// @param amount Calculated keeper fee
Expand All @@ -218,4 +291,33 @@ abstract contract Controller_Incentivized is Controller, IRelayer, Kept {
// transfer DSU to the Controller, such that Kept can transfer to keeper
DSU.pull(account, raisedKeeperFee);
}
}

modifier keepCollateralAccount(
address account,
bytes memory applicableCalldata,
UFixed6 maxFee,
uint256 bufferMultiplier
) {
bytes memory data = abi.encode(getAccountAddress(account), maxFee);
uint256 startGas = gasleft();

_;

uint256 applicableGas = startGas - gasleft();

_handleKeeperFee(
bufferMultiplier > 0
? KeepConfig(
keepConfigBuffered.multiplierBase,
keepConfigBuffered.bufferBase * (bufferMultiplier),
keepConfigBuffered.multiplierCalldata,
keepConfigBuffered.bufferCalldata * (bufferMultiplier)
)
: keepConfig,
applicableGas,
applicableCalldata,
0,
data
);
}
}
Loading

0 comments on commit cf7ae15

Please sign in to comment.