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

V3 MVP Feature Base #892

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
de73c89
add controlled mint/burn to synth
leomassazza Apr 11, 2022
d2ffd95
Abstract authorization and propagate to SNX and Synth
leomassazza Apr 11, 2022
22d6b6c
Use authorization to mint
leomassazza Apr 12, 2022
30516f2
Bootstrap AccountModule (#895)
leomassazza Apr 21, 2022
d55dfc9
Bootstrap FundModule (#897)
leomassazza Apr 21, 2022
8aaf2c6
V3-mvp/base-account-and-fund-interface (#904)
leomassazza May 10, 2022
6007936
V3-mvp/fund (#926)
leomassazza May 24, 2022
30fdbab
merge
dbeal-eth May 26, 2022
2576c21
add multicall module, finalize initial cannonfile
dbeal-eth May 26, 2022
ad6e956
Merge remote-tracking branch 'origin/main' into feature-v3-mvp
mjlescano May 31, 2022
7d77fed
update package-lock
mjlescano May 31, 2022
04e6b85
Merge remote-tracking branch 'origin/main' into feature-v3-mvp
mjlescano May 31, 2022
4fa4bf2
update deploy script to use new multicall abi task (#1008)
mjlescano Jun 2, 2022
6fc73c7
Add MulDivUp Math util (#1015)
leomassazza Jun 7, 2022
f5fcf54
Change AccountModule.createAccount to AccountToken.mint (#1016)
leomassazza Jun 7, 2022
ea9fc10
Add views for account liquidity items (#1020)
leomassazza Jun 8, 2022
4edbdd5
Mint next account (#1019)
noahlitvin Jun 8, 2022
89a8559
fix issues with deployment and oracle price resolve
dbeal-eth Jun 13, 2022
3598ea9
Fixes for onboarding (#1027)
noahlitvin Jun 14, 2022
3511853
upgrade cannon
noahlitvin Jun 16, 2022
7bf648d
Split Fund Module (#1024)
leomassazza Jun 27, 2022
362ef81
update getCollateralTypes etc
noahlitvin Jun 27, 2022
7111834
Rename stuff and fix tests
leomassazza Jun 27, 2022
639e1b2
update cannon version
noahlitvin Jul 6, 2022
1720927
Cannonfile Update (#1038)
noahlitvin Jul 11, 2022
7281a68
fix package lock
noahlitvin Jul 11, 2022
c4033ef
cannon update
noahlitvin Jul 14, 2022
3b5ec7e
Market module (#1033)
leomassazza Jul 19, 2022
0d5a184
lint
leomassazza Jul 19, 2022
5323d2d
Add erc721 enumerability (#1040)
sunnyvempati Jul 22, 2022
8d99b33
Cannon fixes (#1042)
sunnyvempati Jul 26, 2022
070d21e
Merge remote-tracking branch 'origin/main' into feature-v3-mvp
dbeal-eth Aug 5, 2022
3f2fa44
fix pkglock
dbeal-eth Aug 5, 2022
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
9,699 changes: 4,381 additions & 5,318 deletions package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IAuthorizable {
function setNewAuthorized(address newNominatedOwner) external;

function authorized() external view returns (address);
}
12 changes: 12 additions & 0 deletions packages/core-contracts/contracts/interfaces/IERC721Enumerable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./IERC721.sol";

interface IERC721Enumerable {
function totalSupply() external view returns (uint256);

function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

function tokenByIndex(uint256 index) external view returns (uint256);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../../token/ERC721Enumerable.sol";

contract ERC721EnumerableMock is ERC721Enumerable {
function initialize(
string memory tokenName,
string memory tokenSymbol,
string memory baseURL
) public {
_initialize(tokenName, tokenSymbol, baseURL);
}

function mintTo(address to, uint256 tokenId) external {
_mint(to, tokenId);
}

function burn(uint256 tokenId) external {
_burn(tokenId);
}

function transfer(
address from,
address to,
uint256 tokenId
) external {
_transfer(from, to, tokenId);
}
}
40 changes: 40 additions & 0 deletions packages/core-contracts/contracts/mocks/utils/MathUtilMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,44 @@ contract MathUtilMock {
function sqrt(uint x) public pure returns (uint z) {
return MathUtil.sqrt(x);
}

function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) public pure returns (uint256) {
return MathUtil.mulDivDown(x, y, denominator);
}

function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) public pure returns (uint256) {
return MathUtil.mulDivUp(x, y, denominator);
}

function mulDecimal(uint256 x, uint256 y) public pure returns (uint256) {
return MathUtil.mulDecimal(x, y);
}

function divDecimal(uint256 x, uint256 y) public pure returns (uint256) {
return MathUtil.divDecimal(x, y);
}

function mulDivDown(
int256 x,
int256 y,
int256 denominator
) public pure returns (int256) {
return MathUtil.mulDivDown(x, y, denominator);
}

function mulDecimal(int256 x, int256 y) public pure returns (int256) {
return MathUtil.mulDecimal(x, y);
}

function divDecimal(int256 x, int256 y) public pure returns (int256) {
return MathUtil.divDecimal(x, y);
}
}
32 changes: 32 additions & 0 deletions packages/core-contracts/contracts/ownership/Authorizable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./AuthorizableMixin.sol";
import "./Ownable.sol";
import "../interfaces/IAuthorizable.sol";
import "../errors/AddressError.sol";
import "../errors/ChangeError.sol";

contract Authorizable is Ownable, IAuthorizable, AuthorizableMixin {
event AuthorizedChanged(address oldAuthorizad, address newAuthorized);

function setNewAuthorized(address newAuthorized) public override onlyOwner {
AuthorizableStore storage store = _authorizableStore();
address oldAuthorized = store.authorized;

if (newAuthorized == address(0)) {
revert AddressError.ZeroAddress();
}

if (newAuthorized == oldAuthorized) {
revert ChangeError.NoChange();
}

store.authorized = newAuthorized;
emit AuthorizedChanged(oldAuthorized, newAuthorized);
}

function authorized() external view override returns (address) {
return _authorizableStore().authorized;
}
}
23 changes: 23 additions & 0 deletions packages/core-contracts/contracts/ownership/AuthorizableMixin.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./AuthorizableStorage.sol";
import "../errors/AccessError.sol";

contract AuthorizableMixin is AuthorizableStorage {
modifier onlyAuthorized() {
_onlyAuthorized();

_;
}

function _onlyAuthorized() internal view {
if (msg.sender != _getAuthorized()) {
revert AccessError.Unauthorized(msg.sender);
}
}

function _getAuthorized() internal view returns (address) {
return _authorizableStore().authorized;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract AuthorizableStorage {
struct AuthorizableStore {
address authorized;
}

function _authorizableStore() internal pure returns (AuthorizableStore storage store) {
assembly {
// bytes32(uint(keccak256("io.synthetix.authorizable")) - 1)
store.slot := 0x9dedc22c2235c6a81df9ead6005a4f8dd57ccea7aabae74741e05fb3542561b6
}
}
}
22 changes: 21 additions & 1 deletion packages/core-contracts/contracts/token/ERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ contract ERC721 is IERC721, IERC721Metadata, ERC721Storage {
revert TokenAlreadyMinted(tokenId);
}

_beforeTransfer(address(0), to, tokenId);

store.balanceOf[to] += 1;
store.ownerOf[tokenId] = to;

Expand All @@ -187,6 +189,8 @@ contract ERC721 is IERC721, IERC721Metadata, ERC721Storage {
ERC721Store storage store = _erc721Store();
address holder = store.ownerOf[tokenId];

_beforeTransfer(holder, address(0), tokenId);

_approve(address(0), tokenId);

store.balanceOf[holder] -= 1;
Expand All @@ -210,13 +214,17 @@ contract ERC721 is IERC721, IERC721Metadata, ERC721Storage {
revert AddressError.ZeroAddress();
}

_beforeTransfer(from, to, tokenId);

// Clear approvals from the previous holder
_approve(address(0), tokenId);

store.balanceOf[from] -= 1;
store.balanceOf[to] += 1;
store.ownerOf[tokenId] = to;

_postTransfer(from, to, tokenId);

emit Transfer(from, to, tokenId);
}

Expand All @@ -230,7 +238,7 @@ contract ERC721 is IERC721, IERC721Metadata, ERC721Storage {
address to,
uint256 tokenId,
bytes memory data
) private returns (bool) {
) internal returns (bool) {
if (AddressUtil.isContract(to)) {
try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
Expand All @@ -241,4 +249,16 @@ contract ERC721 is IERC721, IERC721Metadata, ERC721Storage {
return true;
}
}

function _beforeTransfer(
address from,
address to,
uint256 tokenId // solhint-disable-next-line no-empty-blocks
) internal virtual {}

function _postTransfer(
address from,
address to,
uint256 tokenId // solhint-disable-next-line no-empty-blocks
) internal virtual {}
}
140 changes: 140 additions & 0 deletions packages/core-contracts/contracts/token/ERC721Enumerable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./ERC721.sol";
import "./ERC721EnumerableStorage.sol";
import "../interfaces/IERC721Enumerable.sol";

/*
Reference implementations:
* OpenZeppelin - https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/extensions/ERC721Enumerable.sol
*/

abstract contract ERC721Enumerable is ERC721, ERC721EnumerableStorage, IERC721Enumerable {
error IndexOutOfBounds();

function _initialize(
string memory tokenName,
string memory tokenSymbol,
string memory baseTokenURI
) internal virtual override {
super._initialize(tokenName, tokenSymbol, baseTokenURI);
if (_erc20EnumerableStore().allTokens.length > 0) {
revert InitError.AlreadyInitialized();
}
}

/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
if (ERC721.balanceOf(owner) <= index) {
revert IndexOutOfBounds();
}
return _erc20EnumerableStore().ownedTokens[owner][index];
}

/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() public view virtual override returns (uint256) {
return _erc20EnumerableStore().allTokens.length;
}

/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
if (index >= ERC721Enumerable.totalSupply()) {
revert IndexOutOfBounds();
}
return _erc20EnumerableStore().allTokens[index];
}

function _beforeTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
if (from == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
}

function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = ERC721.balanceOf(to);
_erc20EnumerableStore().ownedTokens[to][length] = tokenId;
_erc20EnumerableStore().ownedTokensIndex[tokenId] = length;
}

/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_erc20EnumerableStore().allTokensIndex[tokenId] = _erc20EnumerableStore().allTokens.length;
_erc20EnumerableStore().allTokens.push(tokenId);
}

/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).

uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
uint256 tokenIndex = _erc20EnumerableStore().ownedTokensIndex[tokenId];

// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _erc20EnumerableStore().ownedTokens[from][lastTokenIndex];

_erc20EnumerableStore().ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_erc20EnumerableStore().ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}

// This also deletes the contents at the last position of the array
delete _erc20EnumerableStore().ownedTokensIndex[tokenId];
delete _erc20EnumerableStore().ownedTokens[from][lastTokenIndex];
}

/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).

uint256 lastTokenIndex = _erc20EnumerableStore().allTokens.length - 1;
uint256 tokenIndex = _erc20EnumerableStore().allTokensIndex[tokenId];

// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = _erc20EnumerableStore().allTokens[lastTokenIndex];

_erc20EnumerableStore().allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_erc20EnumerableStore().allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

// This also deletes the contents at the last position of the array
delete _erc20EnumerableStore().allTokensIndex[tokenId];
_erc20EnumerableStore().allTokens.pop();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ERC721EnumerableStorage {
struct ERC721EnumerableStore {
mapping(uint256 => uint256) ownedTokensIndex;
mapping(uint256 => uint256) allTokensIndex;
mapping(address => mapping(uint256 => uint256)) ownedTokens;
uint256[] allTokens;
}

function _erc20EnumerableStore() internal pure returns (ERC721EnumerableStore storage store) {
assembly {
// bytes32(uint(keccak256("io.synthetix.ERC721Enumerable")) - 1)
store.slot := 0xbb177151bccee46ca610917613ed7b9846647300a31f78f4e1d2108a85c87851
}
}
}
Loading