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

feat: (WIP) Simplified PropellerRouter Sketch #127

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
29 changes: 29 additions & 0 deletions evm/src/propeller-router/ApprovalManagement.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@src/libraries/EfficientERC20.sol";
import "@interfaces/batch-swap-router/IBatchSwapRouterV1Structs.sol";

/**
* @title ApprovalManagement for contracts
* @author PropellerHeads Devs
* @dev Allows a contract to tokens for trading on third party contracts.
*/
contract ApprovalManagement is IBatchSwapRouterV1Structs {
Copy link
Contributor

Choose a reason for hiding this comment

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

let's leave this for now until we get feedback from the users. then we can check how to use permit2

using EfficientERC20 for IERC20;

/**
* @dev Set allowance to several addresses per token for transfer on behalf of this contract.
*/
function _setApprovals(ExternalApproval[] calldata approvals) internal {
for (uint256 i = 0; i < approvals.length; i++) {
IERC20 token = approvals[i].token;
uint256 allowance = approvals[i].allowance;
for (uint256 j = 0; j < approvals[i].addresses.length; j++) {
address beneficiary = approvals[i].addresses[j];
token.safeApprove(beneficiary, allowance);
}
}
}
}
94 changes: 94 additions & 0 deletions evm/src/propeller-router/CallbackVerificationDispatcher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "@interfaces/batch-swap-router/IBatchSwapRouterV1Structs.sol";
import "@interfaces/ICallbackVerifier.sol";

/**
* @title Dispatch callback verification to external contracts
* @author PropellerHeads Devs
* @dev Provides the ability to delegate callback verification to external
* contracts. This allows dynamically adding new supported protocols
* without needing to upgrade any contracts. External contracts will
* be called using delegatecall so they can share state with the main
* contract if needed.
*
* Note Verifier contracts need to implement the ICallbackVerifier interface
*/
contract CallbackVerificationDispatcher is PropellerRouterStructs {
mapping(bytes4 => address) public callbackVerifiers;

/**
* @dev Registers a new callback verifier contract.
*/
function _setCallbackVerifier(bytes4 selector, address target) internal {
callbackVerifiers[selector] = target;
}

/**
* @dev Set multiple callback verifier with a single call.
*/
function _setCallbackVerifierBatch(CallbackVerifierEntry[] calldata batch)
internal
{
for (uint8 i = 0; i < (batch.length); i++) {
callbackVerifiers[batch[i].selector] = batch[i].verifier;
}
}

/**
* @dev Calls a callback verifier. This should revert if the callback verification fails.
* TODO check if we even still need the GenericCallbackHeader if we are hard-coding
* the callbacks for USV3 (which we can do since we don't care about gas and are
* prioritizing simplicity)
* This function returns the offset of the GenericCallbackHeader in data.
* This offset depends on the protocol and is required to parse the callback data in the fallback function.
*/
function _callVerifyCallback(bytes calldata data)
internal
returns (
uint256 amountOwed,
uint256 amountReceived,
address tokenOwed,
uint16 dataOffset
)
{
bytes4 verifySelector = ICallbackVerifier.verifyCallback.selector;
address sender = msg.sender;
address verifier = callbackVerifiers[bytes4(data[:4])];
if (verifier != address(0)) {
assembly {
let ptr := mload(0x40)
let inpSize := add(100, data.length)

// function selector
mstore(ptr, verifySelector)
// sender
mstore(add(ptr, 4), sender)
// offset for dynamic data
mstore(add(ptr, 36), 64)
// dynamic part
// length of byte array
mstore(add(ptr, 68), data.length)
// byte array contents
calldatacopy(add(ptr, 100), add(data.offset, 4), data.length)

//if delegate call successed
if iszero(delegatecall(gas(), verifier, ptr, inpSize, ptr, 128))
{
// forward revert reason
let retSize := returndatasize()
returndatacopy(ptr, 0, retSize)
revert(ptr, retSize)
}
// load returned data in res
amountOwed := mload(ptr)
amountReceived := mload(add(ptr, 32))
tokenOwed := mload(add(ptr, 64))
dataOffset := and(mload(add(ptr, 96)), 0xFFFF)
}
} else {
revert UnknownSelector(bytes4(data[:4]));
}
}
}
Loading
Loading