diff --git a/contracts/connectors/gelato.sol b/contracts/connectors/gelato.sol new file mode 100644 index 0000000..df1099d --- /dev/null +++ b/contracts/connectors/gelato.sol @@ -0,0 +1,399 @@ +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +import { DSMath } from '../common/math.sol'; + + +// Gelato Data Types +struct Provider { + address addr; // if msg.sender == provider => self-Provider + address module; // e.g. DSA Provider Module +} + +struct Condition { + address inst; // can be AddressZero for self-conditional Actions + bytes data; // can be bytes32(0) for self-conditional Actions +} + +enum Operation { Call, Delegatecall } + +enum DataFlow { None, In, Out, InAndOut } + +struct Action { + address addr; + bytes data; + Operation operation; + DataFlow dataFlow; + uint256 value; + bool termsOkCheck; +} + +struct Task { + Condition[] conditions; // optional + Action[] actions; + uint256 selfProviderGasLimit; // optional: 0 defaults to gelatoMaxGas + uint256 selfProviderGasPriceCeil; // optional: 0 defaults to NO_CEIL +} + +struct TaskReceipt { + uint256 id; + address userProxy; + Provider provider; + uint256 index; + Task[] tasks; + uint256 expiryDate; + uint256 cycleId; // auto-filled by GelatoCore. 0 for non-cyclic/chained tasks + uint256 submissionsLeft; +} + +struct TaskSpec { + address[] conditions; // Address: optional AddressZero for self-conditional actions + Action[] actions; + uint256 gasPriceCeil; +} + +// Gelato Interface +interface IGelatoInterface { + + /** + * @dev API to submit a single Task. + */ + function submitTask( + Provider calldata _provider, + Task calldata _task, + uint256 _expiryDate + ) + external; + + + /** + * @dev A Gelato Task Cycle consists of 1 or more Tasks that automatically submit + * the next one, after they have been executed, where the total number of tasks can + * be only be an even number + */ + function submitTaskCycle( + Provider calldata _provider, + Task[] calldata _tasks, + uint256 _expiryDate, + uint256 _cycles + ) + external; + + + /** + * @dev A Gelato Task Chain consists of 1 or more Tasks that automatically submit + * the next one, after they have been executed, where the total number of tasks can + * be an odd number + */ + function submitTaskChain( + Provider calldata _provider, + Task[] calldata _tasks, + uint256 _expiryDate, + uint256 _sumOfRequestedTaskSubmits + ) + external; + + /** + * @dev Cancel multiple tasks at once + */ + function multiCancelTasks(TaskReceipt[] calldata _taskReceipts) external; + + /** + * @dev Whitelist new executor, TaskSpec(s) and Module(s) in one tx + */ + function multiProvide( + address _executor, + TaskSpec[] calldata _taskSpecs, + address[] calldata _modules + ) + external + payable; + + + /** + * @dev De-Whitelist TaskSpec(s), Module(s) and withdraw funds from gelato in one tx + */ + function multiUnprovide( + uint256 _withdrawAmount, + TaskSpec[] calldata _taskSpecs, + address[] calldata _modules + ) + external; +} + + +interface MemoryInterface { + function setUint(uint _id, uint _val) external; + function getUint(uint _id) external returns (uint); +} + +interface EventInterface { + function emitEvent(uint connectorType, uint connectorID, bytes32 eventCode, bytes calldata eventData) external; +} + +contract Helpers { + + /** + * @dev Return Memory Variable Address + */ + function getMemoryAddr() internal pure returns (address) { + return 0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F; // InstaMemory Address + } + + /** + * @dev Return InstaEvent Address. + */ + function getEventAddr() internal pure returns (address) { + return 0x2af7ea6Cb911035f3eb1ED895Cb6692C39ecbA97; // InstaEvent Address + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint setId, uint val) internal { + if (setId != 0) MemoryInterface(getMemoryAddr()).setUint(setId, val); + } + + /** + * @dev Get Uint value from InstaMemory Contract. + */ + function getUint(uint getId, uint val) internal returns (uint returnVal) { + returnVal = getId == 0 ? val : MemoryInterface(getMemoryAddr()).getUint(getId); + } + + /** + * @dev Connector Details + */ + function connectorID() public pure returns(uint _type, uint _id) { + (_type, _id) = (1, 420); + } +} + +contract GelatoHelpers is Helpers, DSMath { + + /** + * @dev Return Gelato Core Address + */ + function getGelatoCoreAddr() internal pure returns (address) { + return 0x1d681d76ce96E4d70a88A00EBbcfc1E47808d0b8; // Gelato Core address + } + + /** + * @dev Return Instapp DSA Provider Module Address + */ + function getInstadappProviderModuleAddr() internal pure returns (address) { + return 0x0C25452d20cdFeEd2983fa9b9b9Cf4E81D6f2fE2; // ProviderModuleDSA Address + } + +} + + +contract GelatoResolver is GelatoHelpers { + + event LogMultiProvide(address indexed executor, TaskSpec[] indexed taskspecs, address[] indexed modules, uint256 ethToDeposit, uint256 getId, uint256 setId); + + event LogSubmitTask(Provider indexed provider, Task indexed task, uint256 indexed expiryDate, uint256 getId, uint256 setId); + + event LogSubmitTaskCycle(Provider indexed provider, Task[] indexed tasks, uint256 indexed expiryDate, uint256 getId, uint256 setId); + + event LogSubmitTaskChain(Provider indexed provider, Task[] indexed tasks, uint256 indexed expiryDate, uint256 getId, uint256 setId); + + event LogMultiUnprovide(TaskSpec[] indexed taskspecs, address[] indexed modules, uint256 ethToWithdraw, uint256 getId, uint256 setId); + + event LogMultiCancelTasks(TaskReceipt[] indexed taskReceipt, uint256 getId, uint256 setId); + + + // ===== Gelato ENTRY APIs ====== + + /** + * @dev Enables first time users to pre-fund eth, whitelist an executor & register the + * ProviderModuleDSA.sol to be able to use Gelato + * @param _executor address of single execot node or gelato'S decentralized execution market + * @param _taskSpecs enables external providers to whitelist TaskSpecs on gelato + * @param _modules address of ProviderModuleDSA + * @param _ethToDeposit amount of eth to deposit on Gelato, only for self-providers + */ + function multiProvide( + address _executor, + TaskSpec[] calldata _taskSpecs, + address[] calldata _modules, + uint256 _ethToDeposit, + uint256 _getId, + uint256 _setId + ) + external + payable + { + uint256 ethToDeposit = getUint(_getId, _ethToDeposit); + IGelatoInterface(getGelatoCoreAddr()).multiProvide{value: ethToDeposit}( + _executor, + _taskSpecs, + _modules + ); + + setUint(_setId, ethToDeposit); + + emit LogMultiProvide(_executor, _taskSpecs, _modules, ethToDeposit, _getId, _setId); + bytes32 _eventCode = keccak256( + "LogMultiProvide(address,(address[],(address,bytes,uint8,uint8,uint256,bool)[],uint256)[],address[],uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_executor, _taskSpecs, _modules, ethToDeposit, _getId, _setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + /** + * @dev Submits a single, one-time task to Gelato + * @param _provider Consists of proxy module address (DSA) and provider address () + * who will pay for the transaction execution + * @param _task Task specifying the condition and the action connectors + * @param _expiryDate Default 0, othweise timestamp after which the task expires + */ + function submitTask( + Provider calldata _provider, + Task calldata _task, + uint256 _expiryDate + ) + external + payable + { + IGelatoInterface(getGelatoCoreAddr()).submitTask(_provider, _task, _expiryDate); + + emit LogSubmitTask(_provider, _task, _expiryDate, 0, 0); + bytes32 _eventCode = keccak256( + "LogSubmitTask((address,address),((address,bytes)[],(address,bytes,uint8,uint8,uint256,bool)[],uint256,uint256),uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_provider, _task, _expiryDate, 0, 0); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + /** + * @dev Submits single or mulitple Task Sequences to Gelato + * @param _provider Consists of proxy module address (DSA) and provider address () + * who will pay for the transaction execution + * @param _tasks A sequence of Tasks, can be a single or multiples + * @param _expiryDate Default 0, othweise timestamp after which the task expires + * @param _cycles How often the Task List should be executed, e.g. 5 times + */ + function submitTaskCycle( + Provider calldata _provider, + Task[] calldata _tasks, + uint256 _expiryDate, + uint256 _cycles + ) + external + payable + { + IGelatoInterface(getGelatoCoreAddr()).submitTaskCycle( + _provider, + _tasks, + _expiryDate, + _cycles + ); + + emit LogSubmitTaskCycle(_provider, _tasks, _expiryDate, 0, 0); + bytes32 _eventCode = keccak256( + "LogSubmitTaskCycle((address,address),((address,bytes)[],(address,bytes,uint8,uint8,uint256,bool)[],uint256,uint256)[],uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_provider, _tasks, _expiryDate, 0, 0); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + /** + * @dev Submits single or mulitple Task Chains to Gelato + * @param _provider Consists of proxy module address (DSA) and provider address () + * who will pay for the transaction execution + * @param _tasks A sequence of Tasks, can be a single or multiples + * @param _expiryDate Default 0, othweise timestamp after which the task expires + * @param _sumOfRequestedTaskSubmits The TOTAL number of Task auto-submits + * that should have occured once the cycle is complete + */ + function submitTaskChain( + Provider calldata _provider, + Task[] calldata _tasks, + uint256 _expiryDate, + uint256 _sumOfRequestedTaskSubmits + ) + external + payable + { + IGelatoInterface(getGelatoCoreAddr()).submitTaskChain( + _provider, + _tasks, + _expiryDate, + _sumOfRequestedTaskSubmits + ); + + emit LogSubmitTaskChain(_provider, _tasks, _expiryDate, 0, 0); + bytes32 _eventCode = keccak256( + "LogSubmitTaskChain((address,address),((address,bytes)[],(address,bytes,uint8,uint8,uint256,bool)[],uint256,uint256)[],uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_provider, _tasks, _expiryDate, 0, 0); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + // ===== Gelato EXIT APIs ====== + + /** + * @dev Withdraws funds from Gelato, de-whitelists TaskSpecs and Provider Modules + * in one tx + * @param _withdrawAmount Amount of ETH to withdraw from Gelato + * @param _taskSpecs List of Task Specs to de-whitelist, default empty [] + * @param _modules List of Provider Modules to de-whitelist, default empty [] + */ + function multiUnprovide( + uint256 _withdrawAmount, + TaskSpec[] calldata _taskSpecs, + address[] calldata _modules, + uint256 _getId, + uint256 _setId + ) + external + payable + { + uint256 withdrawAmount = getUint(_getId, _withdrawAmount); + uint256 balanceBefore = address(this).balance; + IGelatoInterface(getGelatoCoreAddr()).multiUnprovide( + withdrawAmount, + _taskSpecs, + _modules + ); + uint256 actualWithdrawAmount = sub(address(this).balance, balanceBefore); + setUint(_setId, actualWithdrawAmount); + + emit LogMultiUnprovide(_taskSpecs, _modules, actualWithdrawAmount, _getId, _setId); + bytes32 _eventCode = keccak256( + "LogMultiUnprovide(address,(address[],(address,bytes,uint8,uint8,uint256,bool)[],uint256)[],address[],uint256,uint256,uint256)" + ); + bytes memory _eventParam = abi.encode(_taskSpecs, _modules, actualWithdrawAmount, _getId, _setId); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } + + /** + * @dev Cancels outstanding Tasks + * @param _taskReceipts List of Task Receipts to cancel + */ + function multiCancelTasks(TaskReceipt[] calldata _taskReceipts) + external + payable + { + IGelatoInterface(getGelatoCoreAddr()).multiCancelTasks(_taskReceipts); + + emit LogMultiCancelTasks(_taskReceipts, 0, 0); + bytes32 _eventCode = keccak256( + "LogMultiCancelTasks((uint256,address,(address,address),uint256,((address,bytes)[],(address,bytes,uint8,uint8,uint256,bool)[],uint256,uint256)[],uint256,uint256,uint256)[])" + ); + bytes memory _eventParam = abi.encode(_taskReceipts, 0, 0); + (uint256 _type, uint256 _id) = connectorID(); + EventInterface(getEventAddr()).emitEvent(_type, _id, _eventCode, _eventParam); + } +} + + +contract ConnectGelato is GelatoResolver { + string public name = "Gelato-v1.0"; +} \ No newline at end of file