Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Fix relayer quota payment #155

Merged
merged 4 commits into from
Jun 18, 2024
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
1 change: 1 addition & 0 deletions packages/relayer/certora/conf/relayer.conf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"optimistic_loop": true,
"packages": [
"@mimic-fi/v3-authorizer=../../node_modules/@mimic-fi/v3-authorizer",
"@mimic-fi/v3-helpers=../../node_modules/@mimic-fi/v3-helpers",
"@mimic-fi/v3-smart-vault=../../node_modules/@mimic-fi/v3-smart-vault",
"@mimic-fi/v3-tasks=../../node_modules/@mimic-fi/v3-tasks",
"@openzeppelin=../../node_modules/@openzeppelin"
Expand Down
10 changes: 8 additions & 2 deletions packages/relayer/certora/helpers/Helpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@

pragma solidity ^0.8.0;

import '@mimic-fi/v3-helpers/contracts/utils/Denominations.sol';
import '@mimic-fi/v3-helpers/contracts/utils/ERC20Helpers.sol';
import '@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol';
import '@mimic-fi/v3-tasks/contracts/interfaces/ITask.sol';

contract Helpers {
function balanceOf(address account) external view returns (uint256) {
return address(account).balance;
function NATIVE_TOKEN() external pure returns (address) {
return Denominations.NATIVE_TOKEN;
}

function balanceOf(address token, address account) external view returns (uint256) {
return ERC20Helpers.balanceOf(token, account);
}

function areValidTasks(address[] memory tasks) external view returns (bool) {
Expand Down
48 changes: 37 additions & 11 deletions packages/relayer/certora/specs/Relayer.spec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ using Depositor as Depositor;

methods {
// Helpers
function helpers.balanceOf(address) external returns (uint256) envfree;
function helpers.NATIVE_TOKEN() external returns (address) envfree => ALWAYS(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function helpers.balanceOf(address,address) external returns (uint256) envfree;
function helpers.areValidTasks(address[]) external returns (bool) envfree;

// Relayer
Expand All @@ -20,11 +21,13 @@ methods {
function getSmartVaultCollector(address) external returns (address) envfree;
function getSmartVaultMaxQuota(address) external returns (uint256) envfree;
function getSmartVaultUsedQuota(address) external returns (uint256) envfree;
function getApplicableCollector(address) external returns (address) envfree;
function payTransactionGasToRelayer(address,uint256) external envfree;

// Wildcard entries
function _.smartVault() external => PER_CALLEE_CONSTANT;
function _.hasPermissions(address) external => PER_CALLEE_CONSTANT;
function _.balanceOf(address) external => DISPATCHER(true);
}


Expand Down Expand Up @@ -96,7 +99,7 @@ hook Sstore currentContract.getSmartVaultBalance[KEY address smartVault] uint256
/************************************************************/

invariant contractBalanceIsSumOfBalances()
ghostSumOfSmartVaultBalances <= helpers.balanceOf(currentContract)
ghostSumOfSmartVaultBalances <= helpers.balanceOf(helpers.NATIVE_TOKEN(), currentContract)
filtered { f -> f.selector != SIMULATE() }
{ preserved with (env e) { require e.msg.sender != currentContract; } }

Expand Down Expand Up @@ -265,20 +268,30 @@ rule depositValidAmount(env e, address smartVault, uint256 amount)
}

rule depositProperBalances(env e, address smartVault, uint256 amount)
good_description "After calling `deposit` the smart vault balance is increased at most by `amount`"
good_description "After calling `deposit` smart vault, relayer and collector balances are increased properly"
{
require e.msg.sender != currentContract;

address collector = getApplicableCollector(smartVault);
require collector != e.msg.sender;
require collector != currentContract;

uint256 initialSmartVaultBalance = getSmartVaultBalance(smartVault);
uint256 initialRelayerBalance = helpers.balanceOf(currentContract);
uint256 initialRelayerBalance = helpers.balanceOf(helpers.NATIVE_TOKEN(), currentContract);
uint256 initCollectorBalance = helpers.balanceOf(helpers.NATIVE_TOKEN(), collector);
uint256 initialUsedQuota = getSmartVaultUsedQuota(smartVault);

deposit(e, smartVault, amount);

uint256 currentSmartVaultBalance = getSmartVaultBalance(smartVault);
uint256 currentRelayerBalance = helpers.balanceOf(currentContract);
uint256 currentRelayerBalance = helpers.balanceOf(helpers.NATIVE_TOKEN(), currentContract);
uint256 currentCollectorBalance = helpers.balanceOf(helpers.NATIVE_TOKEN(), collector);
uint256 currentUsedQuota = getSmartVaultUsedQuota(smartVault);
mathint quotaPaid = initialUsedQuota - currentUsedQuota;

assert to_mathint(currentSmartVaultBalance) <= initialSmartVaultBalance + amount;
assert to_mathint(currentRelayerBalance) == initialRelayerBalance + amount;
assert to_mathint(currentSmartVaultBalance) == initialSmartVaultBalance + amount - quotaPaid;
assert to_mathint(currentRelayerBalance) == initialRelayerBalance + amount - quotaPaid;
assert to_mathint(currentCollectorBalance) == initCollectorBalance + quotaPaid;
}

rule payQuotaProperBalances(env e, address smartVault, uint256 amount)
Expand Down Expand Up @@ -306,12 +319,12 @@ rule withdrawProperBalances(env e, uint256 amount)
good_description "After calling `withdraw` the smart vault balance is decreased by `amount`"
{
uint256 initialSmartVaultBalance = getSmartVaultBalance(e.msg.sender);
uint256 initialRelayerBalance = helpers.balanceOf(currentContract);
uint256 initialRelayerBalance = helpers.balanceOf(helpers.NATIVE_TOKEN(), currentContract);

withdraw(e, amount);

uint256 currentSmartVaultBalance = getSmartVaultBalance(e.msg.sender);
uint256 currentRelayerBalance = helpers.balanceOf(currentContract);
uint256 currentRelayerBalance = helpers.balanceOf(helpers.NATIVE_TOKEN(), currentContract);

assert to_mathint(currentSmartVaultBalance) == initialSmartVaultBalance - amount;
assert to_mathint(currentRelayerBalance) == initialRelayerBalance - amount;
Expand All @@ -326,10 +339,10 @@ rule withdrawIntegrity(env e, uint256 amount)
uint256 smartVaultBalance = getSmartVaultBalance(e.msg.sender);
require amount <= smartVaultBalance;

uint256 relayerBalance = helpers.balanceOf(currentContract);
uint256 relayerBalance = helpers.balanceOf(helpers.NATIVE_TOKEN(), currentContract);
require relayerBalance >= amount;

uint256 senderBalance = helpers.balanceOf(e.msg.sender);
uint256 senderBalance = helpers.balanceOf(helpers.NATIVE_TOKEN(), e.msg.sender);
require senderBalance + amount <= MAX_UINT256();

withdraw@withrevert(e, amount);
Expand Down Expand Up @@ -412,3 +425,16 @@ rule simulateAlwaysReverts(env e, address[] tasks, bytes[] data, bool continueIf

assert lastReverted;
}

rule notLockedFunds(env e, method f, calldataarg args, address token)
filtered { f -> f.selector == EXECUTE() || f.selector == DEPOSIT() || f.selector == WITHDRAW() }
good_description "There is always a way to withdraw tokens from the contract"
{
uint256 initialBalance = helpers.balanceOf(token, currentContract);
require initialBalance > 0;

f(e, args);

uint256 currentBalance = helpers.balanceOf(token, currentContract);
satisfy currentBalance == 0;
}
2 changes: 2 additions & 0 deletions packages/relayer/contracts/Relayer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ contract Relayer is IRelayer, Ownable {
quotaPaid = toDeposit;
}

(bool paySuccess, ) = getApplicableCollector(smartVault).call{ value: quotaPaid }('');
if (!paySuccess) revert RelayerQuotaPaymentFailed(smartVault, quotaPaid);
emit QuotaPaid(smartVault, quotaPaid);
}
}
5 changes: 5 additions & 0 deletions packages/relayer/contracts/interfaces/IRelayer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ interface IRelayer {
*/
error RelayerPaymentFailed(address smartVault, uint256 amount, uint256 quota);

/**
* @dev It failed to send owed quota to the smart vault's collector
*/
error RelayerQuotaPaymentFailed(address smartVault, uint256 quota);

/**
* @dev The smart vault balance is lower than the amount to withdraw
*/
Expand Down
Loading
Loading