Skip to content

Commit 23549b5

Browse files
authored
Wrap Module V2 (#123)
* add WrapModuleV2 * add deploys * add integration tests for WrapModuleV2 * add compound wrap adapter * add yearn wrap adapter * add approval on unwrap * review fixes * add comment about why we approve on unwrap
1 parent f6db6ad commit 23549b5

File tree

14 files changed

+2475
-1
lines changed

14 files changed

+2475
-1
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Copyright 2021 Set Labs Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
16+
SPDX-License-Identifier: Apache License, Version 2.0
17+
*/
18+
pragma solidity 0.6.10;
19+
20+
21+
/**
22+
* @title IWrapV2Adapter
23+
* @author Set Protocol
24+
*/
25+
interface IWrapV2Adapter {
26+
27+
function ETH_TOKEN_ADDRESS() external view returns (address);
28+
29+
function getWrapCallData(
30+
address _underlyingToken,
31+
address _wrappedToken,
32+
uint256 _underlyingUnits,
33+
address _to,
34+
bytes memory _wrapData
35+
) external view returns (address _subject, uint256 _value, bytes memory _calldata);
36+
37+
function getUnwrapCallData(
38+
address _underlyingToken,
39+
address _wrappedToken,
40+
uint256 _wrappedTokenUnits,
41+
address _to,
42+
bytes memory _unwrapData
43+
) external view returns (address _subject, uint256 _value, bytes memory _calldata);
44+
45+
function getSpenderAddress(address _underlyingToken, address _wrappedToken) external view returns(address);
46+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
Copyright 2021 Set Labs Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
16+
SPDX-License-Identifier: Apache License, Version 2.0
17+
*/
18+
19+
pragma solidity 0.6.10;
20+
21+
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
22+
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
23+
24+
25+
/**
26+
* @title WrapV2AdapterMock
27+
* @author Set Protocol
28+
*
29+
* ERC20 contract that doubles as a wrap token. The wrapToken accepts any underlying token and
30+
* mints/burns the WrapAdapter Token.
31+
*/
32+
contract WrapV2AdapterMock is ERC20 {
33+
34+
address public constant ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
35+
36+
/* ============ Constructor ============ */
37+
constructor() public ERC20("WrapV2Adapter", "WRAPV2") {}
38+
39+
/* ============ External Functions ============ */
40+
41+
/**
42+
* Mints tokens to the sender of the underlying quantity
43+
*/
44+
function deposit(address _underlyingToken, uint256 _underlyingQuantity) payable external {
45+
// Do a transferFrom of the underlyingToken
46+
if (_underlyingToken != ETH_TOKEN_ADDRESS) {
47+
IERC20(_underlyingToken).transferFrom(msg.sender, address(this), _underlyingQuantity);
48+
}
49+
50+
_mint(msg.sender, _underlyingQuantity);
51+
}
52+
53+
/**
54+
* Burns tokens from the sender of the wrapped asset and returns the underlying
55+
*/
56+
function withdraw(address _underlyingToken, uint256 _underlyingQuantity) external {
57+
// Transfer the underlying to the sender
58+
if (_underlyingToken == ETH_TOKEN_ADDRESS) {
59+
msg.sender.transfer(_underlyingQuantity);
60+
} else {
61+
IERC20(_underlyingToken).transfer(msg.sender, _underlyingQuantity);
62+
}
63+
64+
_burn(msg.sender, _underlyingQuantity);
65+
}
66+
67+
/**
68+
* Generates the calldata to wrap an underlying asset into a wrappedToken.
69+
*
70+
* @param _underlyingToken Address of the component to be wrapped
71+
* @param _underlyingUnits Total quantity of underlying units to wrap
72+
*
73+
* @return _subject Target contract address
74+
* @return _value Total quantity of underlying units (if underlying is ETH)
75+
* @return _calldata Wrap calldata
76+
*/
77+
function getWrapCallData(
78+
address _underlyingToken,
79+
address /* _wrappedToken */,
80+
uint256 _underlyingUnits,
81+
address /* _to */,
82+
bytes memory /* _wrapData */
83+
) external view returns (address _subject, uint256 _value, bytes memory _calldata) {
84+
uint256 value = _underlyingToken == ETH_TOKEN_ADDRESS ? _underlyingUnits : 0;
85+
bytes memory callData = abi.encodeWithSignature("deposit(address,uint256)", _underlyingToken, _underlyingUnits);
86+
return (address(this), value, callData);
87+
}
88+
89+
/**
90+
* Generates the calldata to unwrap a wrapped asset into its underlying.
91+
*
92+
* @param _underlyingToken Address of the underlying of the component to be unwrapped
93+
* @param _wrappedTokenUnits Total quantity of wrapped token units to unwrap
94+
*
95+
* @return _subject Target contract address
96+
* @return _value Total quantity of wrapped token units to unwrap. This will always be 0 for unwrapping
97+
* @return _calldata Unwrap calldata
98+
*/
99+
function getUnwrapCallData(
100+
address _underlyingToken,
101+
address /* _wrappedToken */,
102+
uint256 _wrappedTokenUnits,
103+
address /* _to */,
104+
bytes memory /* _wrapData */
105+
) external view returns (address _subject, uint256 _value, bytes memory _calldata) {
106+
bytes memory callData = abi.encodeWithSignature("withdraw(address,uint256)", _underlyingToken, _wrappedTokenUnits);
107+
return (address(this), 0, callData);
108+
}
109+
110+
/**
111+
* Returns the address to approve source tokens for wrapping.
112+
*
113+
* @return address Address of the contract to approve tokens to
114+
*/
115+
function getSpenderAddress(
116+
address /* _underlyingToken */,
117+
address /* _wrappedToken */
118+
) external view returns(address) {
119+
return address(this);
120+
}
121+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
Copyright 2021 Set Labs Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
16+
SPDX-License-Identifier: Apache License, Version 2.0
17+
*/
18+
19+
pragma solidity 0.6.10;
20+
pragma experimental "ABIEncoderV2";
21+
22+
import { ICErc20 } from "../../../interfaces/external/ICErc20.sol";
23+
import { Compound } from "../lib/Compound.sol";
24+
25+
/**
26+
* @title CompoundWrapV2Adapter
27+
* @author Set Protocol
28+
*
29+
* Wrap adapter for Compound that returns data for wraps/unwraps of tokens
30+
*/
31+
contract CompoundWrapV2Adapter {
32+
using Compound for ICErc20;
33+
34+
35+
/* ============ Constants ============ */
36+
37+
// Compound Mock address to indicate ETH. ETH is used directly in Compound protocol (instead of an abstraction such as WETH)
38+
address public constant ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
39+
40+
/* ============ External Getter Functions ============ */
41+
42+
/**
43+
* Generates the calldata to wrap an underlying asset into a wrappedToken.
44+
*
45+
* @param _underlyingToken Address of the component to be wrapped
46+
* @param _wrappedToken Address of the desired wrapped token
47+
* @param _underlyingUnits Total quantity of underlying units to wrap
48+
*
49+
* @return address Target contract address
50+
* @return uint256 Total quantity of underlying units (if underlying is ETH)
51+
* @return bytes Wrap calldata
52+
*/
53+
function getWrapCallData(
54+
address _underlyingToken,
55+
address _wrappedToken,
56+
uint256 _underlyingUnits,
57+
address /* _to */,
58+
bytes memory /* _wrapData */
59+
)
60+
external
61+
pure
62+
returns (address, uint256, bytes memory)
63+
{
64+
uint256 value;
65+
bytes memory callData;
66+
if (_underlyingToken == ETH_TOKEN_ADDRESS) {
67+
value = _underlyingUnits;
68+
( , , callData) = ICErc20(_wrappedToken).getMintCEtherCalldata(_underlyingUnits);
69+
} else {
70+
value = 0;
71+
( , , callData) = ICErc20(_wrappedToken).getMintCTokenCalldata(_underlyingUnits);
72+
}
73+
74+
return (_wrappedToken, value, callData);
75+
}
76+
77+
/**
78+
* Generates the calldata to unwrap a wrapped asset into its underlying.
79+
*
80+
* @param _wrappedToken Address of the component to be unwrapped
81+
* @param _wrappedTokenUnits Total quantity of wrapped token units to unwrap
82+
*
83+
* @return address Target contract address
84+
* @return uint256 Total quantity of wrapped token units to unwrap. This will always be 0 for unwrapping
85+
* @return bytes Unwrap calldata
86+
*/
87+
function getUnwrapCallData(
88+
address /* _underlyingToken */,
89+
address _wrappedToken,
90+
uint256 _wrappedTokenUnits,
91+
address /* _to */,
92+
bytes memory /* _unwrapData */
93+
)
94+
external
95+
pure
96+
returns (address, uint256, bytes memory)
97+
{
98+
( , , bytes memory callData) = ICErc20(_wrappedToken).getRedeemCalldata(_wrappedTokenUnits);
99+
return (_wrappedToken, 0, callData);
100+
}
101+
102+
/**
103+
* Returns the address to approve source tokens for wrapping.
104+
* @param _wrappedToken Address of the wrapped token
105+
* @return address Address of the contract to approve tokens to
106+
*/
107+
function getSpenderAddress(address /* _underlyingToken */, address _wrappedToken) external pure returns(address) {
108+
return address(_wrappedToken);
109+
}
110+
111+
}

0 commit comments

Comments
 (0)