Skip to content

Commit

Permalink
Merge pull request #451 from equilibria-xyz/ed/92-keeper-configs
Browse files Browse the repository at this point in the history
Fix issue with keeper compensation
  • Loading branch information
EdNoepel authored Oct 4, 2024
2 parents 75cccea + 2b43fc8 commit 6e77481
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 165 deletions.
7 changes: 5 additions & 2 deletions packages/perennial-account/contracts/Controller_Arbitrum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import { Controller_Incentivized } from "./Controller_Incentivized.sol";
contract Controller_Arbitrum is Controller_Incentivized, Kept_Arbitrum {
/// @dev Creates instance of Controller which compensates keepers
/// @param implementation Pristine collateral account contract
constructor(address implementation, IVerifierBase nonceManager)
Controller_Incentivized(implementation, nonceManager) {}
/// @param nonceManager Verifier contract to which nonce and group cancellations are relayed
constructor(
address implementation,
IVerifierBase nonceManager
) Controller_Incentivized(implementation, nonceManager) {}

/// @dev Use the Kept_Arbitrum implementation for calculating the dynamic fee
function _calldataFee(
Expand Down
201 changes: 152 additions & 49 deletions packages/perennial-account/contracts/Controller_Incentivized.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,79 +34,117 @@ 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
constructor(address implementation_, IVerifierBase nonceManager_)
Controller(implementation_) {
/// @param nonceManager_ Verifier contract to which nonce and group cancellations are relayed
constructor(
address implementation_,
IVerifierBase nonceManager_
) Controller(implementation_) {
nonceManager = nonceManager_;
}

/// @notice Configures message verification and keeper compensation
/// @param marketFactory_ Contract used to validate delegated signers
/// @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(
IMarketFactory marketFactory_,
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);
marketFactory = marketFactory_;
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 @@ -117,7 +155,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 @@ -126,13 +170,20 @@ 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);
_ensureValidSigner(message.action.common.account, message.action.common.signer);

_compensateKeeper(message.action);

// relay the message to Verifier
nonceManager.cancelNonceWithSignature(message.nonceCancellation, innerSignature);
}
Expand All @@ -142,13 +193,20 @@ 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);
_ensureValidSigner(message.action.common.account, message.action.common.signer);

_compensateKeeper(message.action);

// relay the message to Verifier
nonceManager.cancelGroupWithSignature(message.groupCancellation, innerSignature);
}
Expand All @@ -158,13 +216,20 @@ 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);
_ensureValidSigner(message.action.common.account, message.action.common.signer);

_compensateKeeper(message.action);

// relay the message to MarketFactory
marketFactory.updateOperatorWithSignature(message.operatorUpdate, innerSignature);
}
Expand All @@ -174,13 +239,20 @@ 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);
_ensureValidSigner(message.action.common.account, message.action.common.signer);

_compensateKeeper(message.action);

// relay the message to MarketFactory
marketFactory.updateSignerWithSignature(message.signerUpdate, innerSignature);
}
Expand All @@ -190,22 +262,24 @@ 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);
_ensureValidSigner(message.action.common.account, message.action.common.signer);

_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 @@ -224,4 +298,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
);
}
}
1 change: 0 additions & 1 deletion packages/perennial-account/test/helpers/arbitrumHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
IOracleProvider,
GasOracle__factory,
} from '../../types/generated'
import { IKept } from '../../types/generated/contracts/Controller_Arbitrum'
import { impersonate } from '../../../common/testutil'
import { IVerifier } from '@equilibria/perennial-v2/types/generated'

Expand Down
Loading

0 comments on commit 6e77481

Please sign in to comment.