Skip to content

Instantly share code, notes, and snippets.

@plutoegg
Created January 27, 2022 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plutoegg/17b8ebabb95aeb32929c2d2449feaae8 to your computer and use it in GitHub Desktop.
Save plutoegg/17b8ebabb95aeb32929c2d2449feaae8 to your computer and use it in GitHub Desktop.
PseudoCode for self-custodial Polygon swaps made via the deversifi UI
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
import "../node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "./libraries/TransferHelper.sol";
/**
* Deversifi polygon contract for holding user's balances self-custodially while facilitating quick and cheap swaps using only signatures
*/
contract DVFPolygonSwapContract is OwnableUpgradeable {
mapping(address => bool) public authorized;
mapping(string => bool) public processedTradeIds;
modifier _isAuthorized() {
require(
authorized[msg.sender],
"UNAUTHORIZED"
);
_;
}
modifier _validateTradeId(string calldata tradeId) {
require(
bytes(tradeId).length > 0,
"Trade ID is required"
);
require(
!processedTradeIds[tradeId],
"Trade ID Already processed"
);
_;
}
event BridgedTrade(address indexed user, address indexed purchasedtoken, uint256 purchasedamount, address indexed soldToken, uint256 soldAmount);
function initialize() public initializer {
__Ownable_init();
authorized[_msgSender()] = true;
}
/**
* @dev Make a swap on behalf of user with their signature on Polygon with Quickswap
* NOTE: Validates that the user signed permission for this in the deversifi UI
* NOTE: After a successful swap, update the user's record on this contract of their new balance, so they could withdraw new balance if they chose
*/
function makeSwapForUser(
address _trader,
address _tokenFrom,
uint _amountFrom,
address _tokenTo,
uint _amountTo,
uint _signatureValidUntilBlock,
uint8 v,
bytes32 r,
bytes32 s,
string calldata tradeId
) external _isAuthorized _validateTradeId(tradeId) {
require(getBalance(_tokenFrom, msg.sender)) >= _amountFrom);
require(_signatureValidUntilBlock > block.number);
require(isValidSignature(keccak256(msg.sender, _tokenFrom, ...etc, ...etc), v, r, s));
makeSwapOnQuickSwap();
updateUserBalanceRecord(_trader,_tokenTo, _amountTo);
}
/**
* @dev withdraw all of the ERC20 token from the contract address to the self-custodial owner
* NOTE: normally not to be used, and not made available in our UI, but available to maintain self-custody
*/
function withdraw(address token) external
{
uint amount = getBalance(token, msg.sender);
TransferHelper.safeTransfer(token, msg.sender, amount);
}
function isValidSignature(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
)
public
constant
returns (bool)
{
return isSigner[ecrecover(
keccak256("\x19Ethereum Signed Message:\n32", hash),
v,
r,
s
)];
}
function keccak(address _trader, address _tokenFrom, uint _amountFrom, address _tokenTo, uint _amountTo, uint _validTill) public constant returns(bytes32) {
return keccak256(_trader, _tokenFrom, _tokenTo, _amountTo, _validTill);
}
/**
* @dev add or remove authorized users
* NOTE: only owner
*/
function authorize(address user, bool value) external onlyOwner {
authorized[user] = value;
}
function transferOwner(address newOwner) external onlyOwner {
authorized[newOwner] = true;
authorized[owner()] = false;
transferOwnership(newOwner);
}
function renounceOwnership() public view override onlyOwner {
require(false, "Unable to renounce ownership");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment