Skip to content

Commit

Permalink
feat: cl keeper registration implementation, link obtain using uni v3
Browse files Browse the repository at this point in the history
  • Loading branch information
kostyamospan committed May 29, 2024
1 parent cd7b643 commit dfbf574
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 8 deletions.
32 changes: 25 additions & 7 deletions contracts/SmartWalletFactoryV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,46 @@ import "@openzeppelin/contracts/proxy/Clones.sol";
import "./SmartWalletV1.sol";

Check warning on line 5 in contracts/SmartWalletFactoryV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

global import of path ./SmartWalletV1.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)

contract SmartWaletFactoryV1 {
struct CreateParams {
address linkToken;
address clRegistrar;
address clRegistry;
address uniswapV3Router;
address wethToken;
bytes wethToLinkSwapPath;
address[] initAllowlist;
}

address public immutable implementation;

Check warning on line 18 in contracts/SmartWalletFactoryV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

Immutable variables name are set to be in capitalized SNAKE_CASE
uint256 public counter;

constructor(address _implementation) {
implementation = _implementation;
}

function createWallet(
address[] calldata initAllowlist
CreateParams calldata params
) external returns (address) {
SmartWalletV1 wallet = SmartWalletV1(Clones.clone(implementation));
wallet.initialize(msg.sender, initAllowlist);
return address(wallet);
return create2Wallet(params, keccak256(abi.encodePacked(counter++)));
}

function create2Wallet(
address[] calldata initAllowlist,
CreateParams calldata params,
bytes32 salt
) external returns (address) {
) public returns (address) {
SmartWalletV1 wallet = SmartWalletV1(
Clones.cloneDeterministic(implementation, salt)
);
wallet.initialize(msg.sender, initAllowlist);
wallet.initialize(
msg.sender,
params.linkToken,
params.clRegistrar,
params.clRegistry,
params.uniswapV3Router,
params.wethToken,
params.wethToLinkSwapPath,
params.initAllowlist
);
return address(wallet);
}

Expand Down
97 changes: 97 additions & 0 deletions contracts/SmartWalletV1.sol
Original file line number Diff line number Diff line change
@@ -1,20 +1,57 @@
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.23;

import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol";

Check warning on line 4 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

imported name LinkTokenInterface is not used
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

Check warning on line 5 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

global import of path @openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

Check warning on line 6 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

global import of path @openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)
import "@openzeppelin/contracts/utils/Address.sol";

Check warning on line 7 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

global import of path @openzeppelin/contracts/utils/Address.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)
// import "@chainlink/contracts/src/v0.8/.sol";
import "./libraries/EnumerableMap.sol";

Check warning on line 9 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

global import of path ./libraries/EnumerableMap.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)
import "./libraries/UniswapV3Actions.sol";
import "./interfaces/IWeth.sol";

import "hardhat/console.sol";

Check failure on line 13 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

Unexpected import of console file

struct RegistrationParams {
string name;
bytes encryptedEmail;
address upkeepContract;
uint32 gasLimit;
address adminAddress;
uint8 triggerType;
bytes checkData;
bytes triggerConfig;
bytes offchainConfig;
uint96 amount;
}

interface AutomationRegistrarInterface {
function registerUpkeep(
RegistrationParams calldata requestParams
) external returns (uint256);
}

interface AutomationRegistryInterface {
function addFunds(uint256 id, uint96 amount) external;
}

contract SmartWalletV1 is OwnableUpgradeable {
using EnumerableMap for EnumerableMap.UintToAutoExecuteMap;

uint256 constant LINK_FEE_PER_AUTOEXECUTE = 0.1e18;

Check failure on line 41 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

'LINK_FEE_PER_AUTOEXECUTE' should start with _
uint32 constant AUTOEXECUTE_GAS_LIMIT = 5_000_000;

Check failure on line 42 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

'AUTOEXECUTE_GAS_LIMIT' should start with _

mapping(address => bool) public allowlist;
mapping(address => mapping(bytes4 => bool)) public blacklistedFunctions;
EnumerableMap.UintToAutoExecuteMap autoExecutesMap;

Check failure on line 46 in contracts/SmartWalletV1.sol

View workflow job for this annotation

GitHub Actions / codestyle

'autoExecutesMap' should start with _
address public linkToken;
address public clRegistrar;
address public clRegistry;
address public uniswapV3Router;
address public wethToken;
uint256 public autoExecuteCounter;
uint256 public upkeepId;
bytes public wethToLinkSwapPath;

modifier onlyAllowlist() {
require(allowlist[msg.sender], "SW: not a blacklister");
Expand All @@ -27,10 +64,24 @@ contract SmartWalletV1 is OwnableUpgradeable {

function initialize(
address _owner,
address _linkToken,
address _clRegistrar,
address _clRegistry,
address _uniswapV3Router,
address _wethToken,
bytes calldata _wethToLinkSwapPath,
address[] calldata _initialAllowList
) external initializer {
__Ownable_init(_owner);

uniswapV3Router = _uniswapV3Router;
wethToken = _wethToken;
wethToLinkSwapPath = _wethToLinkSwapPath;

linkToken = _linkToken;
clRegistrar = _clRegistrar;
clRegistry = _clRegistry;

for (uint i; i < _initialAllowList.length; i++) {
allowlist[_initialAllowList[i]] = true;
}
Expand Down Expand Up @@ -70,6 +121,8 @@ contract SmartWalletV1 is OwnableUpgradeable {

require(executeAfter > block.timestamp, "SW: invalid execute time");

_fundClUpkeep(LINK_FEE_PER_AUTOEXECUTE);

AutoExecute memory data = AutoExecute({
id: ++autoExecuteCounter,
creator: msg.sender,
Expand All @@ -83,6 +136,50 @@ contract SmartWalletV1 is OwnableUpgradeable {
autoExecutesMap.set(data.id, data);
}

function _fundClUpkeep(uint256 amountLink) private {
uint256 linkBalance = IERC20(linkToken).balanceOf(address(this));

if (linkBalance < amountLink) {
IWETH(wethToken).deposit{value: address(this).balance}();

uint256 amountIn = UniswapV3Actions.swapExactOutput(
uniswapV3Router,
wethToLinkSwapPath,
address(this),
amountLink - linkBalance,
0
);

IWETH(wethToken).withdraw(amountIn);
}

IERC20(linkToken).approve(address(clRegistrar), amountLink);

if (upkeepId == 0) {
RegistrationParams memory params = RegistrationParams({
name: "",
encryptedEmail: "",
upkeepContract: address(this),
gasLimit: AUTOEXECUTE_GAS_LIMIT,
adminAddress: address(this),
triggerType: 0,
checkData: "",
triggerConfig: "",
offchainConfig: "",
amount: uint96(LINK_FEE_PER_AUTOEXECUTE)
});

upkeepId = AutomationRegistrarInterface(clRegistrar).registerUpkeep(
params
);
} else {
AutomationRegistryInterface(clRegistry).addFunds(
upkeepId,
uint96(amountLink)
);
}
}

function addToAllowlist(address addr) public onlyOwner {
allowlist[addr] = true;
}
Expand Down
29 changes: 29 additions & 0 deletions contracts/interfaces/IUniswapRouterV3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IUniswapRouterV3 {
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}

struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}

function exactInput(
ExactInputParams calldata params
) external payable returns (uint256 amountOut);

function exactOutput(
ExactOutputParams calldata params
) external payable returns (uint256 amountIn);
}
9 changes: 9 additions & 0 deletions contracts/interfaces/IWeth.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IWETH {
function deposit() external payable;

function withdraw(uint wad) external;

Check warning on line 8 in contracts/interfaces/IWeth.sol

View workflow job for this annotation

GitHub Actions / codestyle

Rule is set with explicit type [var/s: uint]
}
40 changes: 40 additions & 0 deletions contracts/libraries/UniswapV3Actions.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../interfaces/IUniswapRouterV3.sol";

Check warning on line 3 in contracts/libraries/UniswapV3Actions.sol

View workflow job for this annotation

GitHub Actions / codestyle

global import of path ../interfaces/IUniswapRouterV3.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)

library UniswapV3Actions {
function swap(
address _router,
bytes memory _path,
address _recipient,
uint256 _amount
) internal returns (uint256 amountOut) {
IUniswapRouterV3.ExactInputParams memory swapParams = IUniswapRouterV3
.ExactInputParams({
path: _path,
recipient: _recipient,
deadline: block.timestamp,
amountIn: _amount,
amountOutMinimum: 0
});
return IUniswapRouterV3(_router).exactInput(swapParams);
}

function swapExactOutput(
address _router,
bytes memory _path,
address _recipient,
uint256 _amountOut,
uint256 _amountInMaximum
) internal returns (uint256 amountIn) {
IUniswapRouterV3.ExactOutputParams memory swapParams = IUniswapRouterV3
.ExactOutputParams({
path: _path,
recipient: _recipient,
deadline: block.timestamp,
amountOut: _amountOut,
amountInMaximum: _amountInMaximum
});
return IUniswapRouterV3(_router).exactOutput(swapParams);
}
}
2 changes: 1 addition & 1 deletion docs/main.js

Large diffs are not rendered by default.

0 comments on commit dfbf574

Please sign in to comment.