From 57e07c8d10242e552d4e60ef09d6294b1cfe79ce Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 16 Sep 2022 18:04:07 -0700 Subject: [PATCH] formatting sol files --- .prettierignore | 4 + .prettierrc | 16 + .solhint.json | 4 +- packages/contracts/src/Config.sol | 16 +- packages/contracts/src/Counter.sol | 16 +- packages/contracts/src/Proxy.sol | 679 ++++++++---------- packages/contracts/src/Storage.sol | 76 +- .../src/interfaces/IFeeRuleRegistry.sol | 55 +- packages/contracts/src/interfaces/IProxy.sol | 16 +- .../contracts/src/interfaces/IRegistry.sol | 36 +- packages/contracts/src/lib/LibCache.sol | 82 +-- packages/contracts/src/lib/LibFeeStorage.sol | 101 ++- packages/contracts/src/lib/LibParam.sol | 102 +-- packages/contracts/src/lib/LibStack.sol | 93 ++- 14 files changed, 644 insertions(+), 652 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..4ffbd0b --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +node_modules +packages/contracts/lib +cache +out \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..2caa982 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,16 @@ +{ + "printWidth": 100, + "trailingComma": "es5", + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "overrides": [ + { + "files": "*.sol", + "options": { + "semi": true, + "printWidth": 100 + } + } + ] +} diff --git a/.solhint.json b/.solhint.json index ea14bb2..11b3647 100644 --- a/.solhint.json +++ b/.solhint.json @@ -1,6 +1,6 @@ { - "extends": "solhint:recommended", + "plugins": ["prettier"], "rules": { - "compiler-version": ["error", "^0.8.0"] + "prettier/prettier": "error" } } diff --git a/packages/contracts/src/Config.sol b/packages/contracts/src/Config.sol index c15b0bd..b22f821 100644 --- a/packages/contracts/src/Config.sol +++ b/packages/contracts/src/Config.sol @@ -3,12 +3,16 @@ pragma solidity ^0.8.13; contract Config { - // function signature of "postProcess()" - bytes4 public constant POSTPROCESS_SIG = 0xc2722916; + // function signature of "postProcess()" + bytes4 public constant POSTPROCESS_SIG = 0xc2722916; - // The base amount of percentage function - uint256 public constant PERCENTAGE_BASE = 1 ether; + // The base amount of percentage function + uint256 public constant PERCENTAGE_BASE = 1 ether; - // Handler post-process type. Others should not happen now. - enum HandlerType {Token, Custom, Others} + // Handler post-process type. Others should not happen now. + enum HandlerType { + Token, + Custom, + Others + } } diff --git a/packages/contracts/src/Counter.sol b/packages/contracts/src/Counter.sol index 39841a1..e329718 100644 --- a/packages/contracts/src/Counter.sol +++ b/packages/contracts/src/Counter.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.13; // Credits to https://github.com/adrianmcli/web3-vs-ethers contract Counter { - uint public count = 0; + uint256 public count = 0; - function increment() public { - count = count + 1; - } + function increment() public { + count = count + 1; + } - function getCount() public view returns (uint) { - return count; - } -} \ No newline at end of file + function getCount() public view returns (uint256) { + return count; + } +} diff --git a/packages/contracts/src/Proxy.sol b/packages/contracts/src/Proxy.sol index 4441e22..891e06d 100644 --- a/packages/contracts/src/Proxy.sol +++ b/packages/contracts/src/Proxy.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.13; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/Address.sol"; -import "@openzeppelin/contracts/utils/Strings.sol"; -import "./interfaces/IProxy.sol"; -import "./Storage.sol"; -import "./Config.sol"; -import "./lib/LibParam.sol"; -import "./lib/LibStack.sol"; -import "./lib/LibFeeStorage.sol"; -import "./interfaces/IRegistry.sol"; -import "./interfaces/IFeeRuleRegistry.sol"; +import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import '@openzeppelin/contracts/utils/Address.sol'; +import '@openzeppelin/contracts/utils/Strings.sol'; +import './interfaces/IProxy.sol'; +import './Storage.sol'; +import './Config.sol'; +import './lib/LibParam.sol'; +import './lib/LibStack.sol'; +import './lib/LibFeeStorage.sol'; +import './interfaces/IRegistry.sol'; +import './interfaces/IFeeRuleRegistry.sol'; /** * Adapted from furucombo-contract @@ -29,366 +29,321 @@ contract Proxy is IProxy, Storage, Config { event ChargeFee(address indexed tokenIn, uint256 feeAmount); - modifier isNotBanned() { - require(registry.bannedAgents(address(this)) == 0, "Banned"); - _; + modifier isNotBanned() { + require(registry.bannedAgents(address(this)) == 0, 'Banned'); + _; + } + + modifier isNotHalted() { + require(registry.fHalt() == false, 'Halted'); + _; + } + + address private constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + IRegistry public immutable registry; + IFeeRuleRegistry public immutable feeRuleRegistry; + + constructor(address registry_, address feeRuleRegistry_) { + registry = IRegistry(registry_); + feeRuleRegistry = IFeeRuleRegistry(feeRuleRegistry_); + } + + /** + * @notice Direct transfer from EOA should be reverted. + * @dev Callback function will be handled here. + */ + fallback() external payable isNotHalted isNotBanned isInitialized { + // If triggered by a function call, caller should be registered in + // registry. + // The function call will then be forwarded to the location registered + // in registry. + require(_isValidCaller(msg.sender), 'Invalid caller'); + + address target = address(bytes20(registry.callers(msg.sender))); + bytes memory result = _exec(target, msg.data, type(uint256).max); + + // return result for aave v2 flashloan() + uint256 size = result.length; + assembly { + let loc := add(result, 0x20) + return(loc, size) } - - modifier isNotHalted() { - require(registry.fHalt() == false, "Halted"); - _; - } - - address private constant NATIVE_TOKEN = - 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - IRegistry public immutable registry; - IFeeRuleRegistry public immutable feeRuleRegistry; - - constructor(address registry_, address feeRuleRegistry_) { - registry = IRegistry(registry_); - feeRuleRegistry = IFeeRuleRegistry(feeRuleRegistry_); - } - - /** - * @notice Direct transfer from EOA should be reverted. - * @dev Callback function will be handled here. - */ - fallback() external payable isNotHalted isNotBanned isInitialized { - // If triggered by a function call, caller should be registered in - // registry. - // The function call will then be forwarded to the location registered - // in registry. - require(_isValidCaller(msg.sender), "Invalid caller"); - - address target = address(bytes20(registry.callers(msg.sender))); - bytes memory result = _exec(target, msg.data, type(uint256).max); - - // return result for aave v2 flashloan() - uint256 size = result.length; - assembly { - let loc := add(result, 0x20) - return(loc, size) - } - } - - /** - * @notice Direct transfer from EOA should be reverted. - */ - receive() external payable { - require(Address.isContract(msg.sender), "Not allowed from EOA"); - } - - /** - * @notice Combo execution function. Including three phases: pre-process, - * exection and post-process. - * @param tos The handlers of combo. - * @param configs The configurations of executing cubes. - * @param datas The combo datas. - * @param ruleIndexes The indexes of rules. - */ - function batchExec( - address[] calldata tos, - bytes32[] calldata configs, - bytes[] memory datas, - uint256[] calldata ruleIndexes - ) external payable override isNotHalted isNotBanned { - _preProcess(ruleIndexes); - _execs(tos, configs, datas); - _postProcess(); - } - - /** - * @notice The execution interface for callback function to be executed. - * @dev This function can only be called through the handler, which makes - * the caller become proxy itself. - */ - function execs( - address[] calldata tos, - bytes32[] calldata configs, - bytes[] memory datas - ) external payable override isNotHalted isNotBanned isInitialized { - require(msg.sender == address(this), "Does not allow external calls"); - _execs(tos, configs, datas); - } - - /** - * @notice The execution phase. - * @param tos The handlers of combo. - * @param configs The configurations of executing cubes. - * @param datas The combo datas. - */ - function _execs( - address[] memory tos, - bytes32[] memory configs, - bytes[] memory datas - ) internal { - bytes32[256] memory localStack; - uint256 index; - uint256 counter; - - require( - tos.length == datas.length, - "Tos and datas length inconsistent" - ); - require( - tos.length == configs.length, - "Tos and configs length inconsistent" - ); - for (uint256 i = 0; i < tos.length; i++) { - address to = tos[i]; - bytes32 config = configs[i]; - bytes memory data = datas[i]; - // Check if the data contains dynamic parameter - if (!config.isStatic()) { - // If so, trim the exectution data base on the configuration and stack content - _trim(data, config, localStack, index); - } - - // Check if the output will be referenced afterwards - bytes memory result = _exec(to, data, counter); - counter++; - - if (config.isReferenced()) { - // If so, parse the output and place it into local stack - uint256 num = config.getReturnNum(); - uint256 newIndex = _parse(localStack, result, index); - require( - newIndex == index + num, - "Return num and parsed return num not matched" - ); - index = newIndex; - } - - // Setup the process to be triggered in the post-process phase - _setPostProcess(to); - } - } - - /** - * @notice Trimming the execution data. - * @param data The execution data. - * @param config The configuration. - * @param localStack The stack the be referenced. - * @param index Current element count of localStack. - */ - function _trim( - bytes memory data, - bytes32 config, - bytes32[256] memory localStack, - uint256 index - ) internal pure { - // Fetch the parameter configuration from config - (uint256[] memory refs, uint256[] memory params) = config.getParams(); - // Trim the data with the reference and parameters - for (uint256 i = 0; i < refs.length; i++) { - require(refs[i] < index, "Reference to out of localStack"); - bytes32 ref = localStack[refs[i]]; - uint256 offset = params[i]; - uint256 base = PERCENTAGE_BASE; - assembly { - let loc := add(add(data, 0x20), offset) - let m := mload(loc) - // Adjust the value by multiplier if a dynamic parameter is not zero - if iszero(iszero(m)) { - // Assert no overflow first - let p := mul(m, ref) - if iszero(eq(div(p, m), ref)) { - revert(0, 0) - } // require(p / m == ref) - ref := div(p, base) - } - mstore(loc, ref) - } - } + } + + /** + * @notice Direct transfer from EOA should be reverted. + */ + receive() external payable { + require(Address.isContract(msg.sender), 'Not allowed from EOA'); + } + + /** + * @notice Combo execution function. Including three phases: pre-process, + * exection and post-process. + * @param tos The handlers of combo. + * @param configs The configurations of executing cubes. + * @param datas The combo datas. + * @param ruleIndexes The indexes of rules. + */ + function batchExec( + address[] calldata tos, + bytes32[] calldata configs, + bytes[] memory datas, + uint256[] calldata ruleIndexes + ) external payable override isNotHalted isNotBanned { + _preProcess(ruleIndexes); + _execs(tos, configs, datas); + _postProcess(); + } + + /** + * @notice The execution interface for callback function to be executed. + * @dev This function can only be called through the handler, which makes + * the caller become proxy itself. + */ + function execs( + address[] calldata tos, + bytes32[] calldata configs, + bytes[] memory datas + ) external payable override isNotHalted isNotBanned isInitialized { + require(msg.sender == address(this), 'Does not allow external calls'); + _execs(tos, configs, datas); + } + + /** + * @notice The execution phase. + * @param tos The handlers of combo. + * @param configs The configurations of executing cubes. + * @param datas The combo datas. + */ + function _execs( + address[] memory tos, + bytes32[] memory configs, + bytes[] memory datas + ) internal { + bytes32[256] memory localStack; + uint256 index; + uint256 counter; + + require(tos.length == datas.length, 'Tos and datas length inconsistent'); + require(tos.length == configs.length, 'Tos and configs length inconsistent'); + for (uint256 i = 0; i < tos.length; i++) { + address to = tos[i]; + bytes32 config = configs[i]; + bytes memory data = datas[i]; + // Check if the data contains dynamic parameter + if (!config.isStatic()) { + // If so, trim the exectution data base on the configuration and stack content + _trim(data, config, localStack, index); + } + + // Check if the output will be referenced afterwards + bytes memory result = _exec(to, data, counter); + counter++; + + if (config.isReferenced()) { + // If so, parse the output and place it into local stack + uint256 num = config.getReturnNum(); + uint256 newIndex = _parse(localStack, result, index); + require(newIndex == index + num, 'Return num and parsed return num not matched'); + index = newIndex; + } + + // Setup the process to be triggered in the post-process phase + _setPostProcess(to); } - - /** - * @notice Parse the return data to the local stack. - * @param localStack The local stack to place the return values. - * @param ret The return data. - * @param index The current tail. - */ - function _parse( - bytes32[256] memory localStack, - bytes memory ret, - uint256 index - ) internal pure returns (uint256 newIndex) { - uint256 len = ret.length; - // The return value should be multiple of 32-bytes to be parsed. - require(len % 32 == 0, "illegal length for _parse"); - // Estimate the tail after the process. - newIndex = index + len / 32; - require(newIndex <= 256, "stack overflow"); - assembly { - let offset := shl(5, index) - // Store the data into localStack - for { - let i := 0 - } lt(i, len) { - i := add(i, 0x20) - } { - mstore( - add(localStack, add(i, offset)), - mload(add(add(ret, i), 0x20)) - ) - } + } + + /** + * @notice Trimming the execution data. + * @param data The execution data. + * @param config The configuration. + * @param localStack The stack the be referenced. + * @param index Current element count of localStack. + */ + function _trim( + bytes memory data, + bytes32 config, + bytes32[256] memory localStack, + uint256 index + ) internal pure { + // Fetch the parameter configuration from config + (uint256[] memory refs, uint256[] memory params) = config.getParams(); + // Trim the data with the reference and parameters + for (uint256 i = 0; i < refs.length; i++) { + require(refs[i] < index, 'Reference to out of localStack'); + bytes32 ref = localStack[refs[i]]; + uint256 offset = params[i]; + uint256 base = PERCENTAGE_BASE; + assembly { + let loc := add(add(data, 0x20), offset) + let m := mload(loc) + // Adjust the value by multiplier if a dynamic parameter is not zero + if iszero(iszero(m)) { + // Assert no overflow first + let p := mul(m, ref) + if iszero(eq(div(p, m), ref)) { + revert(0, 0) + } // require(p / m == ref) + ref := div(p, base) } + mstore(loc, ref) + } } - - /** - * @notice The execution of a single cube. - * @param to_ The handler of cube. - * @param data_ The cube execution data. - * @param counter_ The current counter of the cube. - */ - function _exec( - address to_, - bytes memory data_, - uint256 counter_ - ) internal returns (bytes memory result) { - require(_isValidHandler(to_), "Invalid handler"); - bool success; - assembly { - success := delegatecall( - sub(gas(), 5000), - to_, - add(data_, 0x20), - mload(data_), - 0, - 0 - ) - let size := returndatasize() - - result := mload(0x40) - mstore( - 0x40, - add(result, and(add(add(size, 0x20), 0x1f), not(0x1f))) - ) - mstore(result, size) - returndatacopy(add(result, 0x20), 0, size) - } - - if (!success) { - if (result.length < 68) revert("_exec"); - assembly { - result := add(result, 0x04) - } - - if (counter_ == type(uint256).max) { - revert(abi.decode(result, (string))); // Don't prepend counter - } else { - revert( - string( - abi.encodePacked( - counter_.toString(), - "_", - abi.decode(result, (string)) - ) - ) - ); - } - } + } + + /** + * @notice Parse the return data to the local stack. + * @param localStack The local stack to place the return values. + * @param ret The return data. + * @param index The current tail. + */ + function _parse( + bytes32[256] memory localStack, + bytes memory ret, + uint256 index + ) internal pure returns (uint256 newIndex) { + uint256 len = ret.length; + // The return value should be multiple of 32-bytes to be parsed. + require(len % 32 == 0, 'illegal length for _parse'); + // Estimate the tail after the process. + newIndex = index + len / 32; + require(newIndex <= 256, 'stack overflow'); + assembly { + let offset := shl(5, index) + // Store the data into localStack + for { + let i := 0 + } lt(i, len) { + i := add(i, 0x20) + } { + mstore(add(localStack, add(i, offset)), mload(add(add(ret, i), 0x20))) + } } - - /** - * @notice Setup the post-process. - * @param to_ The handler of post-process. - */ - function _setPostProcess(address to_) internal { - // If the stack length equals 0, just skip - // If the top is a custom post-process, replace it with the handler - // address. - if (stack.length == 0) { - return; - } else if ( - stack.peek() == bytes32(bytes12(uint96(HandlerType.Custom))) && - bytes4(stack.peek(1)) != 0x00000000 - ) { - stack.pop(); - stack.setAddress(to_); - stack.setHandlerType(HandlerType.Custom); - } + } + + /** + * @notice The execution of a single cube. + * @param to_ The handler of cube. + * @param data_ The cube execution data. + * @param counter_ The current counter of the cube. + */ + function _exec( + address to_, + bytes memory data_, + uint256 counter_ + ) internal returns (bytes memory result) { + require(_isValidHandler(to_), 'Invalid handler'); + bool success; + assembly { + success := delegatecall(sub(gas(), 5000), to_, add(data_, 0x20), mload(data_), 0, 0) + let size := returndatasize() + + result := mload(0x40) + mstore(0x40, add(result, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + mstore(result, size) + returndatacopy(add(result, 0x20), 0, size) } - /// @notice The pre-process phase. - function _preProcess(uint256[] memory ruleIndexes_) - internal - virtual - isStackEmpty - { - // Set the sender. - _setSender(); - // Set the fee collector - cache._setFeeCollector(feeRuleRegistry.feeCollector()); - // Calculate fee - uint256 feeRate = - feeRuleRegistry.calFeeRateMulti(_getSender(), ruleIndexes_); - require(feeRate <= PERCENTAGE_BASE, "fee rate out of range"); - cache._setFeeRate(feeRate); - if (msg.value > 0 && feeRate > 0) { - // Process ether fee - uint256 feeEth = _calFee(msg.value, feeRate); - - // It will fail if fee collector is gnosis contract, because .transfer() will only consume 2300 gas limit. - // Replacing .transfer() with .call('') to avoid out of gas - address collector = cache._getFeeCollector(); - (bool success, ) = collector.call{value: feeEth}(""); - require(success, "Send fee to collector failed"); - emit ChargeFee(NATIVE_TOKEN, feeEth); - } + if (!success) { + if (result.length < 68) revert('_exec'); + assembly { + result := add(result, 0x04) + } + + if (counter_ == type(uint256).max) { + revert(abi.decode(result, (string))); // Don't prepend counter + } else { + revert(string(abi.encodePacked(counter_.toString(), '_', abi.decode(result, (string))))); + } } - - /// @notice The post-process phase. - function _postProcess() internal { - // Handler type will be parsed at the beginning. Will send the token back to - // user if the handler type is "Token". Will get the handler address and - // execute the customized post-process if handler type is "Custom". - while (stack.length > 0) { - bytes32 top = stack.get(); - // Get handler type - HandlerType handlerType = HandlerType(uint96(bytes12(top))); - if (handlerType == HandlerType.Token) { - address addr = address(uint160(uint256(top))); - uint256 tokenAmount = IERC20(addr).balanceOf(address(this)); - if (tokenAmount > 0) - IERC20(addr).safeTransfer(msg.sender, tokenAmount); - } else if (handlerType == HandlerType.Custom) { - address addr = stack.getAddress(); - _exec( - addr, - abi.encodeWithSelector(POSTPROCESS_SIG), - type(uint256).max - ); - } else { - revert("Invalid handler type"); - } - } - - // Balance should also be returned to user - uint256 amount = address(this).balance; - if (amount > 0) payable(msg.sender).transfer(amount); - - // Reset cached datas - cache._resetFeeCollector(); - cache._resetFeeRate(); - _resetSender(); + } + + /** + * @notice Setup the post-process. + * @param to_ The handler of post-process. + */ + function _setPostProcess(address to_) internal { + // If the stack length equals 0, just skip + // If the top is a custom post-process, replace it with the handler + // address. + if (stack.length == 0) { + return; + } else if ( + stack.peek() == bytes32(bytes12(uint96(HandlerType.Custom))) && + bytes4(stack.peek(1)) != 0x00000000 + ) { + stack.pop(); + stack.setAddress(to_); + stack.setHandlerType(HandlerType.Custom); } - - /// @notice Check if the handler is valid in registry. - function _isValidHandler(address handler) internal view returns (bool) { - return registry.isValidHandler(handler); + } + + /// @notice The pre-process phase. + function _preProcess(uint256[] memory ruleIndexes_) internal virtual isStackEmpty { + // Set the sender. + _setSender(); + // Set the fee collector + cache._setFeeCollector(feeRuleRegistry.feeCollector()); + // Calculate fee + uint256 feeRate = feeRuleRegistry.calFeeRateMulti(_getSender(), ruleIndexes_); + require(feeRate <= PERCENTAGE_BASE, 'fee rate out of range'); + cache._setFeeRate(feeRate); + if (msg.value > 0 && feeRate > 0) { + // Process ether fee + uint256 feeEth = _calFee(msg.value, feeRate); + + // It will fail if fee collector is gnosis contract, because .transfer() will only consume 2300 gas limit. + // Replacing .transfer() with .call('') to avoid out of gas + address collector = cache._getFeeCollector(); + (bool success, ) = collector.call{value: feeEth}(''); + require(success, 'Send fee to collector failed'); + emit ChargeFee(NATIVE_TOKEN, feeEth); } - - /// @notice Check if the caller is valid in registry. - function _isValidCaller(address caller) internal view returns (bool) { - return registry.isValidCaller(caller); + } + + /// @notice The post-process phase. + function _postProcess() internal { + // Handler type will be parsed at the beginning. Will send the token back to + // user if the handler type is "Token". Will get the handler address and + // execute the customized post-process if handler type is "Custom". + while (stack.length > 0) { + bytes32 top = stack.get(); + // Get handler type + HandlerType handlerType = HandlerType(uint96(bytes12(top))); + if (handlerType == HandlerType.Token) { + address addr = address(uint160(uint256(top))); + uint256 tokenAmount = IERC20(addr).balanceOf(address(this)); + if (tokenAmount > 0) IERC20(addr).safeTransfer(msg.sender, tokenAmount); + } else if (handlerType == HandlerType.Custom) { + address addr = stack.getAddress(); + _exec(addr, abi.encodeWithSelector(POSTPROCESS_SIG), type(uint256).max); + } else { + revert('Invalid handler type'); + } } - function _calFee(uint256 amount, uint256 feeRate) - internal - pure - returns (uint256) - { - return (amount * feeRate) / PERCENTAGE_BASE; - } -} \ No newline at end of file + // Balance should also be returned to user + uint256 amount = address(this).balance; + if (amount > 0) payable(msg.sender).transfer(amount); + + // Reset cached datas + cache._resetFeeCollector(); + cache._resetFeeRate(); + _resetSender(); + } + + /// @notice Check if the handler is valid in registry. + function _isValidHandler(address handler) internal view returns (bool) { + return registry.isValidHandler(handler); + } + + /// @notice Check if the caller is valid in registry. + function _isValidCaller(address caller) internal view returns (bool) { + return registry.isValidCaller(caller); + } + + function _calFee(uint256 amount, uint256 feeRate) internal pure returns (uint256) { + return (amount * feeRate) / PERCENTAGE_BASE; + } +} diff --git a/packages/contracts/src/Storage.sol b/packages/contracts/src/Storage.sol index c306c9d..c1eac5d 100644 --- a/packages/contracts/src/Storage.sol +++ b/packages/contracts/src/Storage.sol @@ -2,45 +2,45 @@ pragma solidity ^0.8.13; -import "./lib/LibCache.sol"; -import "./lib/LibStack.sol"; +import './lib/LibCache.sol'; +import './lib/LibStack.sol'; /// @notice A cache structure composed by a bytes32 array contract Storage { - using LibCache for mapping(bytes32 => bytes32); - using LibStack for bytes32[]; - - bytes32[] public stack; - mapping(bytes32 => bytes32) public cache; - - // keccak256 hash of "msg.sender" - // prettier-ignore - bytes32 public constant MSG_SENDER_KEY = 0xb2f2618cecbbb6e7468cc0f2aa43858ad8d153e0280b22285e28e853bb9d453a; - - modifier isStackEmpty() { - require(stack.length == 0, "Stack not empty"); - _; - } - - modifier isInitialized() { - require(_getSender() != address(0), "Sender is not initialized"); - _; - } - - modifier isNotInitialized() { - require(_getSender() == address(0), "Sender is initialized"); - _; - } - - function _setSender() internal isNotInitialized { - cache.setAddress(MSG_SENDER_KEY, msg.sender); - } - - function _resetSender() internal { - cache.setAddress(MSG_SENDER_KEY, address(0)); - } - - function _getSender() internal view returns (address) { - return cache.getAddress(MSG_SENDER_KEY); - } + using LibCache for mapping(bytes32 => bytes32); + using LibStack for bytes32[]; + + bytes32[] public stack; + mapping(bytes32 => bytes32) public cache; + + // keccak256 hash of "msg.sender" + // prettier-ignore + bytes32 public constant MSG_SENDER_KEY = 0xb2f2618cecbbb6e7468cc0f2aa43858ad8d153e0280b22285e28e853bb9d453a; + + modifier isStackEmpty() { + require(stack.length == 0, 'Stack not empty'); + _; + } + + modifier isInitialized() { + require(_getSender() != address(0), 'Sender is not initialized'); + _; + } + + modifier isNotInitialized() { + require(_getSender() == address(0), 'Sender is initialized'); + _; + } + + function _setSender() internal isNotInitialized { + cache.setAddress(MSG_SENDER_KEY, msg.sender); + } + + function _resetSender() internal { + cache.setAddress(MSG_SENDER_KEY, address(0)); + } + + function _getSender() internal view returns (address) { + return cache.getAddress(MSG_SENDER_KEY); + } } diff --git a/packages/contracts/src/interfaces/IFeeRuleRegistry.sol b/packages/contracts/src/interfaces/IFeeRuleRegistry.sol index b0c8d0b..e59f3f3 100644 --- a/packages/contracts/src/interfaces/IFeeRuleRegistry.sol +++ b/packages/contracts/src/interfaces/IFeeRuleRegistry.sol @@ -3,22 +3,41 @@ pragma solidity ^0.8.13; interface IFeeRuleRegistry { - /* State Variables Getter */ - function rules(uint256) external view returns (address); - function counter() external view returns (uint256); - function basisFeeRate() external view returns (uint256); - function feeCollector() external view returns (address); - function BASE() external view returns (uint256); - - /* Restricted Functions */ - function setBasisFeeRate(uint256) external; - function setFeeCollector(address) external; - function registerRule(address rule) external; - function unregisterRule(uint256 ruleIndex) external; - - /* View Functions */ - function calFeeRateMulti(address usr, uint256[] calldata ruleIndexes) external view returns (uint256 scaledRate); - function calFeeRate(address usr, uint256 ruleIndex) external view returns (uint256 scaledRate); - function calFeeRateMultiWithoutBasis(address usr, uint256[] calldata ruleIndexes) external view returns (uint256 scaledRate); - function calFeeRateWithoutBasis(address usr, uint256 ruleIndex) external view returns (uint256 scaledRate); + /* State Variables Getter */ + function rules(uint256) external view returns (address); + + function counter() external view returns (uint256); + + function basisFeeRate() external view returns (uint256); + + function feeCollector() external view returns (address); + + function BASE() external view returns (uint256); + + /* Restricted Functions */ + function setBasisFeeRate(uint256) external; + + function setFeeCollector(address) external; + + function registerRule(address rule) external; + + function unregisterRule(uint256 ruleIndex) external; + + /* View Functions */ + function calFeeRateMulti(address usr, uint256[] calldata ruleIndexes) + external + view + returns (uint256 scaledRate); + + function calFeeRate(address usr, uint256 ruleIndex) external view returns (uint256 scaledRate); + + function calFeeRateMultiWithoutBasis(address usr, uint256[] calldata ruleIndexes) + external + view + returns (uint256 scaledRate); + + function calFeeRateWithoutBasis(address usr, uint256 ruleIndex) + external + view + returns (uint256 scaledRate); } diff --git a/packages/contracts/src/interfaces/IProxy.sol b/packages/contracts/src/interfaces/IProxy.sol index 1215508..f1d7e8d 100644 --- a/packages/contracts/src/interfaces/IProxy.sol +++ b/packages/contracts/src/interfaces/IProxy.sol @@ -3,6 +3,16 @@ pragma solidity ^0.8.13; interface IProxy { - function batchExec(address[] calldata tos, bytes32[] calldata configs, bytes[] memory datas, uint256[] calldata ruleIndexes) external payable; - function execs(address[] calldata tos, bytes32[] calldata configs, bytes[] memory datas) external payable; -} \ No newline at end of file + function batchExec( + address[] calldata tos, + bytes32[] calldata configs, + bytes[] memory datas, + uint256[] calldata ruleIndexes + ) external payable; + + function execs( + address[] calldata tos, + bytes32[] calldata configs, + bytes[] memory datas + ) external payable; +} diff --git a/packages/contracts/src/interfaces/IRegistry.sol b/packages/contracts/src/interfaces/IRegistry.sol index 1c59692..c116c9a 100644 --- a/packages/contracts/src/interfaces/IRegistry.sol +++ b/packages/contracts/src/interfaces/IRegistry.sol @@ -3,17 +3,27 @@ pragma solidity ^0.8.13; interface IRegistry { - function handlers(address) external view returns (bytes32); - function callers(address) external view returns (bytes32); - function bannedAgents(address) external view returns (uint256); - function fHalt() external view returns (bool); - function isValidHandler(address handler) external view returns (bool); - function isValidCaller(address handler) external view returns (bool); - - function register(address registration, bytes32 info) external; - function unregister(address registration) external; - function registerCaller(address registration, bytes32 info) external; - function unregisterCaller(address registration) external; - function ban(address agent) external; - function unban(address agent) external; + function handlers(address) external view returns (bytes32); + + function callers(address) external view returns (bytes32); + + function bannedAgents(address) external view returns (uint256); + + function fHalt() external view returns (bool); + + function isValidHandler(address handler) external view returns (bool); + + function isValidCaller(address handler) external view returns (bool); + + function register(address registration, bytes32 info) external; + + function unregister(address registration) external; + + function registerCaller(address registration, bytes32 info) external; + + function unregisterCaller(address registration) external; + + function ban(address agent) external; + + function unban(address agent) external; } diff --git a/packages/contracts/src/lib/LibCache.sol b/packages/contracts/src/lib/LibCache.sol index 39aac37..feb1798 100644 --- a/packages/contracts/src/lib/LibCache.sol +++ b/packages/contracts/src/lib/LibCache.sol @@ -3,49 +3,51 @@ pragma solidity ^0.8.13; library LibCache { - function set( - mapping(bytes32 => bytes32) storage _cache, - bytes32 _key, - bytes32 _value - ) internal { - _cache[_key] = _value; - } + function set( + mapping(bytes32 => bytes32) storage _cache, + bytes32 _key, + bytes32 _value + ) internal { + _cache[_key] = _value; + } - function setAddress( - mapping(bytes32 => bytes32) storage _cache, - bytes32 _key, - address _value - ) internal { - _cache[_key] = bytes32(uint256(uint160(_value))); - } + function setAddress( + mapping(bytes32 => bytes32) storage _cache, + bytes32 _key, + address _value + ) internal { + _cache[_key] = bytes32(uint256(uint160(_value))); + } - function setUint256( - mapping(bytes32 => bytes32) storage _cache, - bytes32 _key, - uint256 _value - ) internal { - _cache[_key] = bytes32(_value); - } + function setUint256( + mapping(bytes32 => bytes32) storage _cache, + bytes32 _key, + uint256 _value + ) internal { + _cache[_key] = bytes32(_value); + } - function getAddress( - mapping(bytes32 => bytes32) storage _cache, - bytes32 _key - ) internal view returns (address ret) { - ret = address(uint160(uint256(_cache[_key]))); - } + function getAddress(mapping(bytes32 => bytes32) storage _cache, bytes32 _key) + internal + view + returns (address ret) + { + ret = address(uint160(uint256(_cache[_key]))); + } - function getUint256( - mapping(bytes32 => bytes32) storage _cache, - bytes32 _key - ) internal view returns (uint256 ret) { - ret = uint256(_cache[_key]); - } + function getUint256(mapping(bytes32 => bytes32) storage _cache, bytes32 _key) + internal + view + returns (uint256 ret) + { + ret = uint256(_cache[_key]); + } - function get(mapping(bytes32 => bytes32) storage _cache, bytes32 _key) - internal - view - returns (bytes32 ret) - { - ret = _cache[_key]; - } + function get(mapping(bytes32 => bytes32) storage _cache, bytes32 _key) + internal + view + returns (bytes32 ret) + { + ret = _cache[_key]; + } } diff --git a/packages/contracts/src/lib/LibFeeStorage.sol b/packages/contracts/src/lib/LibFeeStorage.sol index f201e4a..9acca69 100644 --- a/packages/contracts/src/lib/LibFeeStorage.sol +++ b/packages/contracts/src/lib/LibFeeStorage.sol @@ -2,64 +2,49 @@ pragma solidity ^0.8.13; -import "./LibCache.sol"; -import "../Storage.sol"; +import './LibCache.sol'; +import '../Storage.sol'; library LibFeeStorage { - using LibCache for mapping(bytes32 => bytes32); - - // keccak256 hash of "furucombo.fee.rate" - // prettier-ignore - bytes32 public constant FEE_RATE_KEY = 0x142183525227cae0e4300fd0fc77d7f3b08ceb0fd9cb2a6c5488668fa0ea5ffa; - - // keccak256 hash of "furucombo.fee.collector" - // prettier-ignore - bytes32 public constant FEE_COLLECTOR_KEY = 0x60d7a7cc0a45d852bd613e4f527aaa2e4b81fff918a69a2aab88b6458751d614; - - function _setFeeRate( - mapping(bytes32 => bytes32) storage _cache, - uint256 _feeRate - ) internal { - require(_getFeeRate(_cache) == 0, "Fee rate not zero"); - _cache.setUint256(FEE_RATE_KEY, _feeRate); - } - - function _resetFeeRate(mapping(bytes32 => bytes32) storage _cache) - internal - { - _cache.setUint256(FEE_RATE_KEY, 0); - } - - function _getFeeRate(mapping(bytes32 => bytes32) storage _cache) - internal - view - returns (uint256) - { - return _cache.getUint256(FEE_RATE_KEY); - } - - function _setFeeCollector( - mapping(bytes32 => bytes32) storage _cache, - address _collector - ) internal { - require( - _getFeeCollector(_cache) == address(0), - "Fee collector is initialized" - ); - _cache.setAddress(FEE_COLLECTOR_KEY, _collector); - } - - function _resetFeeCollector(mapping(bytes32 => bytes32) storage _cache) - internal - { - _cache.setAddress(FEE_COLLECTOR_KEY, address(0)); - } - - function _getFeeCollector(mapping(bytes32 => bytes32) storage _cache) - internal - view - returns (address) - { - return _cache.getAddress(FEE_COLLECTOR_KEY); - } + using LibCache for mapping(bytes32 => bytes32); + + // keccak256 hash of "furucombo.fee.rate" + // prettier-ignore + bytes32 public constant FEE_RATE_KEY = 0x142183525227cae0e4300fd0fc77d7f3b08ceb0fd9cb2a6c5488668fa0ea5ffa; + + // keccak256 hash of "furucombo.fee.collector" + // prettier-ignore + bytes32 public constant FEE_COLLECTOR_KEY = 0x60d7a7cc0a45d852bd613e4f527aaa2e4b81fff918a69a2aab88b6458751d614; + + function _setFeeRate(mapping(bytes32 => bytes32) storage _cache, uint256 _feeRate) internal { + require(_getFeeRate(_cache) == 0, 'Fee rate not zero'); + _cache.setUint256(FEE_RATE_KEY, _feeRate); + } + + function _resetFeeRate(mapping(bytes32 => bytes32) storage _cache) internal { + _cache.setUint256(FEE_RATE_KEY, 0); + } + + function _getFeeRate(mapping(bytes32 => bytes32) storage _cache) internal view returns (uint256) { + return _cache.getUint256(FEE_RATE_KEY); + } + + function _setFeeCollector(mapping(bytes32 => bytes32) storage _cache, address _collector) + internal + { + require(_getFeeCollector(_cache) == address(0), 'Fee collector is initialized'); + _cache.setAddress(FEE_COLLECTOR_KEY, _collector); + } + + function _resetFeeCollector(mapping(bytes32 => bytes32) storage _cache) internal { + _cache.setAddress(FEE_COLLECTOR_KEY, address(0)); + } + + function _getFeeCollector(mapping(bytes32 => bytes32) storage _cache) + internal + view + returns (address) + { + return _cache.getAddress(FEE_COLLECTOR_KEY); + } } diff --git a/packages/contracts/src/lib/LibParam.sol b/packages/contracts/src/lib/LibParam.sol index b4e6d4d..50efde7 100644 --- a/packages/contracts/src/lib/LibParam.sol +++ b/packages/contracts/src/lib/LibParam.sol @@ -3,61 +3,61 @@ pragma solidity ^0.8.13; library LibParam { - bytes32 private constant STATIC_MASK = - 0x0100000000000000000000000000000000000000000000000000000000000000; - bytes32 private constant PARAMS_MASK = - 0x0000000000000000000000000000000000000000000000000000000000000001; - bytes32 private constant REFS_MASK = - 0x00000000000000000000000000000000000000000000000000000000000000FF; - bytes32 private constant RETURN_NUM_MASK = - 0x00FF000000000000000000000000000000000000000000000000000000000000; + bytes32 private constant STATIC_MASK = + 0x0100000000000000000000000000000000000000000000000000000000000000; + bytes32 private constant PARAMS_MASK = + 0x0000000000000000000000000000000000000000000000000000000000000001; + bytes32 private constant REFS_MASK = + 0x00000000000000000000000000000000000000000000000000000000000000FF; + bytes32 private constant RETURN_NUM_MASK = + 0x00FF000000000000000000000000000000000000000000000000000000000000; - uint256 private constant REFS_LIMIT = 22; - uint256 private constant PARAMS_SIZE_LIMIT = 64; - uint256 private constant RETURN_NUM_OFFSET = 240; + uint256 private constant REFS_LIMIT = 22; + uint256 private constant PARAMS_SIZE_LIMIT = 64; + uint256 private constant RETURN_NUM_OFFSET = 240; - function isStatic(bytes32 conf) internal pure returns (bool) { - if (conf & STATIC_MASK == 0) return true; - else return false; - } + function isStatic(bytes32 conf) internal pure returns (bool) { + if (conf & STATIC_MASK == 0) return true; + else return false; + } - function isReferenced(bytes32 conf) internal pure returns (bool) { - if (getReturnNum(conf) == 0) return false; - else return true; - } + function isReferenced(bytes32 conf) internal pure returns (bool) { + if (getReturnNum(conf) == 0) return false; + else return true; + } - function getReturnNum(bytes32 conf) internal pure returns (uint256 num) { - bytes32 temp = (conf & RETURN_NUM_MASK) >> RETURN_NUM_OFFSET; - num = uint256(temp); - } + function getReturnNum(bytes32 conf) internal pure returns (uint256 num) { + bytes32 temp = (conf & RETURN_NUM_MASK) >> RETURN_NUM_OFFSET; + num = uint256(temp); + } - function getParams(bytes32 conf) - internal - pure - returns (uint256[] memory refs, uint256[] memory params) - { - require(!isStatic(conf), "Static params"); - uint256 n = REFS_LIMIT; - while (conf & REFS_MASK == REFS_MASK && n > 0) { - n--; - conf = conf >> 8; - } - require(n > 0, "No dynamic param"); - refs = new uint256[](n); - params = new uint256[](n); - for (uint256 i = 0; i < n; i++) { - refs[i] = uint256(conf & REFS_MASK); - conf = conf >> 8; - } - uint256 locCount = 0; - for (uint256 k = 0; k < PARAMS_SIZE_LIMIT; k++) { - if (conf & PARAMS_MASK != 0) { - require(locCount < n, "Location count exceeds ref count"); - params[locCount] = k * 32 + 4; - locCount++; - } - conf = conf >> 1; - } - require(locCount == n, "Location count less than ref count"); + function getParams(bytes32 conf) + internal + pure + returns (uint256[] memory refs, uint256[] memory params) + { + require(!isStatic(conf), 'Static params'); + uint256 n = REFS_LIMIT; + while (conf & REFS_MASK == REFS_MASK && n > 0) { + n--; + conf = conf >> 8; + } + require(n > 0, 'No dynamic param'); + refs = new uint256[](n); + params = new uint256[](n); + for (uint256 i = 0; i < n; i++) { + refs[i] = uint256(conf & REFS_MASK); + conf = conf >> 8; + } + uint256 locCount = 0; + for (uint256 k = 0; k < PARAMS_SIZE_LIMIT; k++) { + if (conf & PARAMS_MASK != 0) { + require(locCount < n, 'Location count exceeds ref count'); + params[locCount] = k * 32 + 4; + locCount++; + } + conf = conf >> 1; } + require(locCount == n, 'Location count less than ref count'); + } } diff --git a/packages/contracts/src/lib/LibStack.sol b/packages/contracts/src/lib/LibStack.sol index 01914f9..a130f22 100644 --- a/packages/contracts/src/lib/LibStack.sol +++ b/packages/contracts/src/lib/LibStack.sol @@ -2,59 +2,46 @@ pragma solidity ^0.8.13; -import "../Config.sol"; +import '../Config.sol'; library LibStack { - function setAddress(bytes32[] storage _stack, address _input) internal { - _stack.push(bytes32(uint256(uint160(_input)))); - } - - function set(bytes32[] storage _stack, bytes32 _input) internal { - _stack.push(_input); - } - - function setHandlerType(bytes32[] storage _stack, Config.HandlerType _input) - internal - { - _stack.push(bytes12(uint96(_input))); - } - - function getAddress(bytes32[] storage _stack) - internal - returns (address ret) - { - ret = address(uint160(uint256(peek(_stack)))); - _stack.pop(); - } - - function getSig(bytes32[] storage _stack) internal returns (bytes4 ret) { - ret = bytes4(peek(_stack)); - _stack.pop(); - } - - function get(bytes32[] storage _stack) internal returns (bytes32 ret) { - ret = peek(_stack); - _stack.pop(); - } - - function peek(bytes32[] storage _stack) - internal - view - returns (bytes32 ret) - { - uint256 length = _stack.length; - require(length > 0, "stack empty"); - ret = _stack[length - 1]; - } - - function peek(bytes32[] storage _stack, uint256 _index) - internal - view - returns (bytes32 ret) - { - uint256 length = _stack.length; - require(length > 0, "stack empty"); - require(length > _index, "not enough elements in stack"); - ret = _stack[length - _index - 1]; - } + function setAddress(bytes32[] storage _stack, address _input) internal { + _stack.push(bytes32(uint256(uint160(_input)))); + } + + function set(bytes32[] storage _stack, bytes32 _input) internal { + _stack.push(_input); + } + + function setHandlerType(bytes32[] storage _stack, Config.HandlerType _input) internal { + _stack.push(bytes12(uint96(_input))); + } + + function getAddress(bytes32[] storage _stack) internal returns (address ret) { + ret = address(uint160(uint256(peek(_stack)))); + _stack.pop(); + } + + function getSig(bytes32[] storage _stack) internal returns (bytes4 ret) { + ret = bytes4(peek(_stack)); + _stack.pop(); + } + + function get(bytes32[] storage _stack) internal returns (bytes32 ret) { + ret = peek(_stack); + _stack.pop(); + } + + function peek(bytes32[] storage _stack) internal view returns (bytes32 ret) { + uint256 length = _stack.length; + require(length > 0, 'stack empty'); + ret = _stack[length - 1]; + } + + function peek(bytes32[] storage _stack, uint256 _index) internal view returns (bytes32 ret) { + uint256 length = _stack.length; + require(length > 0, 'stack empty'); + require(length > _index, 'not enough elements in stack'); + ret = _stack[length - _index - 1]; + } }