Skip to content

Commit 84a2aaf

Browse files
authored
ovault: erc20 equivalency (#1571)
Signed-off-by: shankar <shankar@layerzerolabs.org>
1 parent ff15c6e commit 84a2aaf

11 files changed

Lines changed: 417 additions & 81 deletions

File tree

packages/ovault-composer/contracts/ERC20MintBurn.sol

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,41 @@ import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
66
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
77

88
contract ERC20MintBurn is IERC20MintBurnExtension, ERC20, Ownable {
9-
mapping(address => uint256) public approvedMinters;
10-
mapping(address => uint256) public approvedBurners;
11-
address public approvedSpender;
9+
modifier onlySuperUsers() {
10+
if (!superUsers[msg.sender]) {
11+
revert NotSuperUser(msg.sender);
12+
}
13+
_;
14+
}
15+
16+
mapping(address => bool) public superUsers;
1217

1318
bool public constant ERC4626AdapterCompliant = true;
1419

1520
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) Ownable(msg.sender) {}
1621

17-
function setMinter(address _minter, uint256 _amount) external onlyOwner {
18-
approvedMinters[_minter] = _amount;
19-
emit MinterSet(_minter, _amount);
22+
function setSuperUser(address _superUser, bool _status) external onlyOwner {
23+
superUsers[_superUser] = _status;
24+
emit SuperUserSet(_superUser, _status);
2025
}
2126

22-
function setBurner(address _burner, uint256 _amount) external onlyOwner {
23-
approvedBurners[_burner] = _amount;
24-
emit BurnerSet(_burner, _amount);
27+
function mint(address _to, uint256 _amount) external virtual onlySuperUsers {
28+
_mint(_to, _amount);
2529
}
2630

27-
function setSpender(address _spender) external onlyOwner {
28-
approvedSpender = _spender;
29-
emit SpenderSet(_spender);
31+
function burn(address _from, uint256 _amount) external virtual onlySuperUsers {
32+
_burn(_from, _amount);
3033
}
3134

32-
function mint(address _to, uint256 _amount) external {
33-
require(approvedMinters[msg.sender] >= _amount, "ERC20MintBurn: minter not approved");
34-
_mint(_to, _amount);
35+
function transfer(address _from, address _to, uint256 _amount) external onlySuperUsers {
36+
_transfer(_from, _to, _amount);
3537
}
3638

37-
function burn(address _from, uint256 _amount) external {
38-
require(approvedBurners[msg.sender] >= _amount, "ERC20MintBurn: burner not approved");
39-
_burn(_from, _amount);
39+
function spendAllowance(address _owner, address _spender, uint256 _amount) external onlySuperUsers {
40+
_spendAllowance(_owner, _spender, _amount);
4041
}
4142

42-
function spendAllowance(address _owner, address _spender, uint256 _amount) external {
43-
require(msg.sender == approvedSpender, "ERC20MintBurn: spender not approved");
44-
_spendAllowance(_owner, _spender, _amount);
43+
function approve(address owner, address spender, uint256 value) external onlySuperUsers {
44+
_approve(owner, spender, value, true);
4545
}
4646
}

packages/ovault-composer/contracts/ERC4626Adapter.sol

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/ERC2
88
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
99
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
1010

11-
contract ERC4626Adapter is IERC4626Adapter {
11+
contract ERC4626Adapter is IERC4626Adapter, IERC20 {
1212
using Math for uint256;
1313
using SafeERC20 for IERC20;
1414
using SafeERC20 for IERC20MintBurnExtension;
@@ -70,16 +70,41 @@ contract ERC4626Adapter is IERC4626Adapter {
7070
return address(_share);
7171
}
7272

73-
/// @dev Adding to match EIP-4626 Specification
73+
/// @dev Adding to proxy the share token's total supply
7474
function totalSupply() public view virtual returns (uint256) {
7575
return IERC20(share()).totalSupply();
7676
}
7777

78-
/// @dev Adding to match EIP-4626 Specification
78+
/// @dev Adding to proxy the share token's balance of an owner
7979
function balanceOf(address owner) public view virtual returns (uint256) {
8080
return IERC20(share()).balanceOf(owner);
8181
}
8282

83+
/// @dev Adding to proxy the share token's transfer function
84+
function transfer(address to, uint256 value) public virtual returns (bool) {
85+
address owner = msg.sender;
86+
IERC20MintBurnExtension(share()).transfer(owner, to, value);
87+
return true;
88+
}
89+
90+
/// @dev Adding to proxy the share token's allowance function
91+
function allowance(address owner, address spender) public view virtual returns (uint256) {
92+
return IERC20(share()).allowance(owner, spender);
93+
}
94+
95+
/// @dev Adding to proxy the share token's approve function
96+
function approve(address spender, uint256 value) public virtual returns (bool) {
97+
_share.approve(msg.sender, spender, value);
98+
return true;
99+
}
100+
101+
/// @dev Adding to proxy the share token's transferFrom function
102+
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
103+
_share.spendAllowance(from, msg.sender, value);
104+
IERC20MintBurnExtension(share()).transfer(from, to, value);
105+
return true;
106+
}
107+
83108
/** @dev See {IERC4626-totalAssets}. */
84109
function totalAssets() public view virtual returns (uint256) {
85110
return _asset.balanceOf(address(this));

packages/ovault-composer/contracts/OFTMintBurn.sol

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
66
import { IERC20MintBurnExtension } from "./interfaces/IERC20MintBurnExtension.sol";
77

88
contract OFTMintBurn is OFT, IERC20MintBurnExtension {
9-
mapping(address => uint256) public approvedMinters;
10-
mapping(address => uint256) public approvedBurners;
11-
address public approvedSpender;
9+
modifier onlySuperUsers() {
10+
if (!superUsers[msg.sender]) {
11+
revert NotSuperUser(msg.sender);
12+
}
13+
_;
14+
}
15+
16+
mapping(address => bool) public superUsers;
1217

1318
bool public constant ERC4626AdapterCompliant = true;
1419

@@ -19,33 +24,28 @@ contract OFTMintBurn is OFT, IERC20MintBurnExtension {
1924
address _delegate
2025
) OFT(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {}
2126

22-
function setMinter(address _minter, uint256 _amount) external onlyOwner {
23-
approvedMinters[_minter] = _amount;
24-
emit MinterSet(_minter, _amount);
27+
function setSuperUser(address _superUser, bool _status) external onlyOwner {
28+
superUsers[_superUser] = _status;
29+
emit SuperUserSet(_superUser, _status);
2530
}
2631

27-
function setBurner(address _burner, uint256 _amount) external onlyOwner {
28-
approvedBurners[_burner] = _amount;
29-
emit BurnerSet(_burner, _amount);
32+
function mint(address _to, uint256 _amount) external onlySuperUsers {
33+
_mint(_to, _amount);
3034
}
3135

32-
function setSpender(address _spender) external onlyOwner {
33-
approvedSpender = _spender;
34-
emit SpenderSet(_spender);
36+
function burn(address _from, uint256 _amount) external onlySuperUsers {
37+
_burn(_from, _amount);
3538
}
3639

37-
function mint(address _to, uint256 _amount) external {
38-
require(approvedMinters[msg.sender] >= _amount, "ERC20MintBurn: minter not approved");
39-
_mint(_to, _amount);
40+
function spendAllowance(address _owner, address _spender, uint256 _amount) external onlySuperUsers {
41+
_spendAllowance(_owner, _spender, _amount);
4042
}
4143

42-
function burn(address _from, uint256 _amount) external {
43-
require(approvedBurners[msg.sender] >= _amount, "ERC20MintBurn: burner not approved");
44-
_burn(_from, _amount);
44+
function transfer(address _from, address _to, uint256 _amount) external onlySuperUsers {
45+
_transfer(_from, _to, _amount);
4546
}
4647

47-
function spendAllowance(address _owner, address _spender, uint256 _amount) external {
48-
require(msg.sender == approvedSpender, "ERC20MintBurn: spender not approved");
49-
_spendAllowance(_owner, _spender, _amount);
48+
function approve(address owner, address spender, uint256 value) external onlySuperUsers {
49+
_approve(owner, spender, value, true);
5050
}
5151
}

packages/ovault-composer/contracts/OVault.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ import { ERC4626Adapter } from "./ERC4626Adapter.sol";
77
import { IOVault } from "./interfaces/IOVault.sol";
88

99
contract OVault is ERC4626Adapter, IOVault {
10+
address public immutable ASSET_OFT;
11+
address public immutable SHARE_OFT;
12+
1013
constructor(IOFT _asset, IOFT _share) ERC4626Adapter(_asset.token(), _share.token()) {
1114
if (!IERC20MintBurnExtension(_share.token()).ERC4626AdapterCompliant()) {
1215
revert ShareNotERC4626AdapterCompliant();
1316
}
17+
18+
ASSET_OFT = address(_asset);
19+
SHARE_OFT = address(_share);
1420
}
1521
}

packages/ovault-composer/contracts/interfaces/IERC20MintBurnExtension.sol

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,19 @@
22
pragma solidity ^0.8.20;
33

44
interface IERC20MintBurnExtension {
5-
event MinterSet(address minter, uint256 amount);
6-
event BurnerSet(address burner, uint256 amount);
7-
event SpenderSet(address spender);
5+
event SuperUserSet(address superUser, bool status);
86

9-
error CanNotMintAmount(address minter, uint256 amount);
10-
error CanNotBurnAmount(address burner, uint256 amount);
11-
error CanNotSpend(address spender);
7+
error NotSuperUser(address sender);
128

13-
function approvedMinters(address minter) external view returns (uint256);
14-
function approvedBurners(address burner) external view returns (uint256);
15-
function approvedSpender() external view returns (address);
9+
function superUsers(address superUser) external view returns (bool);
1610

17-
function setMinter(address minter, uint256 amount) external;
18-
function setBurner(address burner, uint256 amount) external;
19-
function setSpender(address spender) external;
11+
function setSuperUser(address superUser, bool status) external;
2012

2113
function mint(address to, uint256 amount) external;
2214
function burn(address from, uint256 amount) external;
2315
function spendAllowance(address owner, address spender, uint256 amount) external;
16+
function transfer(address from, address to, uint256 amount) external;
17+
function approve(address owner, address spender, uint256 value) external;
2418

2519
function ERC4626AdapterCompliant() external view returns (bool);
2620
}

packages/ovault-composer/contracts/interfaces/IERC4626Adapter.sol

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,6 @@ interface IERC4626Adapter is IERC20Metadata {
5050
*/
5151
function share() external view returns (address assetTokenAddress);
5252

53-
/**
54-
* @dev Returns the total amount of the share token that is “managed” by Vault.
55-
*
56-
* - SHOULD include any compounding that occurs from yield.
57-
* - MUST be inclusive of any fees that are charged against assets in the Vault.
58-
* - MUST NOT revert.
59-
* - Added to match EIP-4626 Specification
60-
*/
61-
function totalSupply() external view returns (uint256 totalManagedShares);
62-
63-
/**
64-
* @dev Returns the amount of shares that the Vault holds for an address.
65-
*
66-
* - MUST NOT revert.
67-
* - Added to match EIP-4626 Specification
68-
*/
69-
function balanceOf(address owner) external view returns (uint256 shares);
70-
7153
/**
7254
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
7355
*

packages/ovault-composer/contracts/interfaces/IOVault.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ pragma solidity ^0.8.20;
33

44
interface IOVault {
55
error ShareNotERC4626AdapterCompliant();
6+
7+
function ASSET_OFT() external view returns (address);
8+
function SHARE_OFT() external view returns (address);
69
}

0 commit comments

Comments
 (0)