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

Entity clarification #35

Merged
merged 13 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
10 changes: 9 additions & 1 deletion per_multicall/script/Vault.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,17 @@ contract VaultScript is Script {
);
console.log("pk per operator", operatorAddress);
console.log("sk per operator", operatorSk);
uint256 feeSplitProtocolDefault = 50 * (10 ** 16);
m30m marked this conversation as resolved.
Show resolved Hide resolved
uint256 feeSplitRelayer = 10 * (10 ** 16);
vm.startBroadcast(skDeployer);
payable(operatorAddress).transfer(0.01 ether);
ExpressRelay multicall = new ExpressRelay(operatorAddress, 0);
// TODO: set admin to xc-admin
ExpressRelay multicall = new ExpressRelay(
operatorAddress,
operatorAddress,
feeSplitProtocolDefault,
feeSplitRelayer
);
vm.stopBroadcast();
console.log("deployed ExpressRelay contract at", address(multicall));
return address(multicall);
Expand Down
3 changes: 3 additions & 0 deletions per_multicall/src/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ error InvalidSignatureLength();
// The new contract does not have the same magic value as the old one.
// Signature: 0x4ed848c1
error InvalidMagicValue();

// Signature: 0x0601f697
error InvalidFeeSplit();
175 changes: 132 additions & 43 deletions per_multicall/src/ExpressRelay.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,142 @@ pragma solidity ^0.8.13;

import "./Errors.sol";
import "./Structs.sol";
import "./ExpressRelayState.sol";

import "openzeppelin-contracts/contracts/utils/Strings.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "@pythnetwork/express-relay-sdk-solidity/IExpressRelay.sol";
import "@pythnetwork/express-relay-sdk-solidity/IExpressRelayFeeReceiver.sol";

contract ExpressRelay is IExpressRelay {
contract ExpressRelay is IExpressRelay, ExpressRelayState {
event ReceivedETH(address sender, uint256 amount);

// TODO: separate the notion operator into relayer and admin.
// TODO: Relayer can submit transactions, admin can change relayers and set fees
address _operator;
mapping(address => uint256) _feeConfig;
mapping(bytes32 => bool) _permissions;
uint256 _defaultFee;

/**
* @notice ExpressRelay constructor - Initializes a new multicall contract with given parameters
*
* @param operator: address of express relay operator EOA
* @param defaultFee: default fee split to be paid to the protocol whose permissioning is being used
* @param admin: address of admin of express relay
* @param relayer: address of relayer EOA
* @param feeSplitProtocolDefault: default fee split to be paid to the protocol whose permissioning is being used
* @param feeSplitRelayer: split of the non-protocol fees to be paid to the relayer
*/
constructor(
address admin,
address relayer,
uint256 feeSplitProtocolDefault,
uint256 feeSplitRelayer
) {
// TODO: move this to ExpressRelayState?
state.feeSplitPrecision = 10 ** 18;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is gonna be constant, let's just make it a constant.


state.admin = admin;
state.relayer = relayer;

if (feeSplitProtocolDefault > state.feeSplitPrecision) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this checking logic can become a separate function

revert InvalidFeeSplit();
}
state.feeSplitProtocolDefault = feeSplitProtocolDefault;

if (feeSplitRelayer > state.feeSplitPrecision) {
revert InvalidFeeSplit();
}
state.feeSplitRelayer = feeSplitRelayer;
}

// TODO: move this to ExpressRelayState/Setters/Getters?
/**
* @notice setRelayer function - sets the relayer
*
* @param relayer: address of the relayer to be set
*/
function setRelayer(address relayer) public onlyAdmin {
state.relayer = relayer;
}

/**
* @notice getRelayer function - returns the address of the relayer
*/
function getRelayer() public view returns (address) {
return state.relayer;
}

/**
* @notice setFeeProtocolDefault function - sets the default fee split for the protocol
*
* @param feeSplit: split of fee to be sent to the protocol. 10**18 is 100%
*/
function setFeeProtocolDefault(uint256 feeSplit) public onlyAdmin {
if (feeSplit > state.feeSplitPrecision) {
revert InvalidFeeSplit();
}
state.feeSplitProtocolDefault = feeSplit;
}

/**
* @notice getFeeProtocolDefault function - returns the default fee split for the protocol
*/
function getFeeProtocolDefault() public view returns (uint256) {
return state.feeSplitProtocolDefault;
}

/**
* @notice setFeeProtocol function - sets the fee split for a given protocol fee recipient
*
* @param feeRecipient: address of the fee recipient for the protocol
* @param feeSplit: split of fee to be sent to the protocol. 10**18 is 100%
*/
function setFeeProtocol(
address feeRecipient,
uint256 feeSplit
) public onlyAdmin {
if (feeSplit > state.feeSplitPrecision) {
revert InvalidFeeSplit();
}
state.feeConfig[feeRecipient] = feeSplit;
}

/**
* @notice getFeeProtocol function - returns the fee split for a given protocol fee recipient
*
* @param feeRecipient: address of the fee recipient for the protocol
*/
function getFeeProtocol(
address feeRecipient
) public view returns (uint256) {
uint256 feeProtocol = state.feeConfig[feeRecipient];
if (feeProtocol == 0) {
feeProtocol = state.feeSplitProtocolDefault;
}
return feeProtocol;
}

/**
* @notice setFeeRelayer function - sets the fee split for the relayer
*
* @param feeSplit: split of remaining fee (after subtracting protocol fee) to be sent to the relayer. 10**18 is 100%
*/
constructor(address operator, uint256 defaultFee) {
_operator = operator;
_defaultFee = defaultFee;
function setFeeRelayer(uint256 feeSplit) public onlyAdmin {
if (feeSplit > state.feeSplitPrecision) {
revert InvalidFeeSplit();
}
state.feeSplitRelayer = feeSplit;
}

/**
* @notice getOperator function - returns the address of the express relay operator
* @notice getFeeRelayer function - returns the fee split for the relayer
*/
function getOperator() public view returns (address) {
return _operator;
function getFeeRelayer() public view returns (uint256) {
return state.feeSplitRelayer;
}

function isPermissioned(
address protocolFeeReceiver,
bytes calldata permissionId
) public view returns (bool permissioned) {
return
_permissions[
state.permissions[
keccak256(abi.encode(protocolFeeReceiver, permissionId))
];
}

/**
* @notice setFee function - sets the fee for a given fee recipient
*
* @param feeRecipient: address of the fee recipient for the contract being registered
* @param feeSplit: amount of fee to be split with the protocol. 10**18 is 100%
*/
function setFee(address feeRecipient, uint256 feeSplit) public {
if (msg.sender != _operator) {
revert Unauthorized();
}
_feeConfig[feeRecipient] = feeSplit;
}

function _isContract(address _addr) private view returns (bool) {
uint32 size;
assembly {
Expand Down Expand Up @@ -88,15 +167,17 @@ contract ExpressRelay is IExpressRelay {
address[] calldata targetContracts,
bytes[] calldata targetCalldata,
uint256[] calldata bidAmounts
) public payable returns (MulticallStatus[] memory multicallStatuses) {
if (msg.sender != _operator) {
revert Unauthorized();
}
)
public
payable
onlyRelayer
returns (MulticallStatus[] memory multicallStatuses)
{
if (permissionKey.length < 20) {
revert InvalidPermission();
}

_permissions[keccak256(permissionKey)] = true;
state.permissions[keccak256(permissionKey)] = true;
multicallStatuses = new MulticallStatus[](targetCalldata.length);

uint256 totalBid = 0;
Expand Down Expand Up @@ -124,14 +205,14 @@ contract ExpressRelay is IExpressRelay {
// use the first 20 bytes of permission as fee receiver
address feeReceiver = _bytesToAddress(permissionKey);
// transfer fee to the protocol
uint256 protocolFee = _feeConfig[feeReceiver];
if (protocolFee == 0) {
protocolFee = _defaultFee;
uint256 feeSplitProtocol = state.feeConfig[feeReceiver];
if (feeSplitProtocol == 0) {
feeSplitProtocol = state.feeSplitProtocolDefault;
}
uint256 feeProtocolNumerator = totalBid * protocolFee;
uint256 feeProtocol;
uint256 feeProtocolNumerator = totalBid * feeSplitProtocol;
if (feeProtocolNumerator > 0) {
uint256 feeProtocol = feeProtocolNumerator /
1000_000_000_000_000_000;
feeProtocol = feeProtocolNumerator / state.feeSplitPrecision;
if (_isContract(feeReceiver)) {
IExpressRelayFeeReceiver(feeReceiver).receiveAuctionProceedings{
value: feeProtocol
Expand All @@ -140,7 +221,15 @@ contract ExpressRelay is IExpressRelay {
payable(feeReceiver).transfer(feeProtocol);
}
}
_permissions[keccak256(permissionKey)] = false;
state.permissions[keccak256(permissionKey)] = false;

// pay the relayer
uint256 feeRelayerNumerator = (totalBid - feeProtocol) *
state.feeSplitRelayer;
if (feeRelayerNumerator > 0) {
uint256 feeRelayer = feeRelayerNumerator / state.feeSplitPrecision;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not calculate this first and check feeRelayer > 0 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

little bit of gas costs savings. in practice this is gonna be minimal, can just divide in same line

payable(state.relayer).transfer(feeRelayer);
}
}

/**
Expand Down
42 changes: 42 additions & 0 deletions per_multicall/src/ExpressRelayState.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (C) 2024 Lavra Holdings Limited - All Rights Reserved
pragma solidity ^0.8.13;

import "./Errors.sol";
import "./Structs.sol";

contract ExpressRelayStorage {
struct State {
// address of admin of express relay
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some of these comments do not help in understanding the fields. Comments here should explain what each variable "does" instead of explaining what each variable "is".

address admin;
// address of relayer EOA
address relayer;
// custom fee splits for protocol fee receivers
mapping(address => uint256) feeConfig;
// permission key flag storage
mapping(bytes32 => bool) permissions;
// default fee split to be paid to the protocol whose permissioning is being used
uint256 feeSplitProtocolDefault;
// split of the non-protocol fees to be paid to the relayer
uint256 feeSplitRelayer;
// precision for fee splits
uint256 feeSplitPrecision;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this not a constant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is set further down--it isn't possible to set a constant within a struct in solidity

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what I mean is to remove it from the state and just have it as a constant in our contracts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it's more clear to have this as a variable than a constant that's reused in multiple places

}
}

contract ExpressRelayState {
ExpressRelayStorage.State state;

modifier onlyAdmin() {
if (msg.sender != state.admin) {
revert Unauthorized();
}
_;
}

modifier onlyRelayer() {
if (msg.sender != state.relayer) {
revert Unauthorized();
}
_;
}
}
1 change: 1 addition & 0 deletions per_multicall/src/OpportunityAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ abstract contract OpportunityAdapter is SigVerify {
/**
* @notice OpportunityAdapter constructor - Initializes a new opportunity adapter contract with given parameters
*
* @param admin: address of admin of opportunity adapter
* @param expressRelay: address of express relay
* @param weth: address of WETH contract
*/
Expand Down
Loading
Loading