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

ERC20 wrapper #38

Merged
merged 34 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9545b43
feat: add erc20 wrapper
amarinkovic Nov 21, 2022
a67bd5b
Revert "fix!: restrict internalTransfer() to transfer between entitie…
amarinkovic Nov 22, 2022
1d2e54f
feat: add erc20 wrapper transfer methods
amarinkovic Nov 22, 2022
a89f39d
test: fix tests after making tokenization mandatory
amarinkovic Nov 22, 2022
95210a8
test: assert several internal transfer requirements
amarinkovic Nov 22, 2022
6692215
feat: wrap entity token
amarinkovic Nov 23, 2022
57d3619
feat: scope certain internal transfers to wrappers only
amarinkovic Nov 23, 2022
6752ec4
refactor: fix facet method names
amarinkovic Nov 23, 2022
06c78f8
feat: diamond address is sender
amarinkovic Nov 23, 2022
266d425
test: token wrapping
amarinkovic Nov 23, 2022
ce8d4b0
fix: wrapper test
amarinkovic Nov 23, 2022
8a526d1
debug CI test
amarinkovic Nov 23, 2022
5831814
Revert "debug CI test"
amarinkovic Nov 23, 2022
d764918
test: basic wrapper props
amarinkovic Nov 23, 2022
03151ee
test: stabilise external deposit fuzzer
amarinkovic Nov 23, 2022
52ea3a8
test-refactor: rename variables
amarinkovic Nov 23, 2022
f869c05
test: wrapper balance; minor code cleanup
amarinkovic Nov 24, 2022
da83c7f
test: wrapper allowance and transfer
amarinkovic Nov 24, 2022
be3d35f
test: assert allowance decreases on transfer, assert reverts for inva…
amarinkovic Nov 24, 2022
04d7293
test: assert wrap requirements
amarinkovic Nov 24, 2022
c1320f1
refactor: use lib to assert entity
amarinkovic Nov 24, 2022
d81f586
feat: wrapper erc20 permit
amarinkovic Nov 24, 2022
e270092
doc: update with natspec changes
amarinkovic Nov 24, 2022
b4d05ea
refactor: remove console import
amarinkovic Nov 28, 2022
e141cec
refactor: store token name and symbol as strings
amarinkovic Nov 28, 2022
515b207
Merge branch 'main' into erc20_wrapper
amarinkovic Nov 28, 2022
8395665
refactor: better method naming for wrapper requirements
amarinkovic Nov 29, 2022
df0aade
refactor: minor naming improvement
amarinkovic Nov 29, 2022
3bc7efd
refactor: add not wrapped already requirement to wrapper constructor
amarinkovic Nov 29, 2022
12f7030
refactor: move wrap token into SystemFacet/LibObject
amarinkovic Nov 29, 2022
9517800
feat: make wrapper non-reentrant
amarinkovic Nov 30, 2022
cc02308
fix: apply check-effects-interactions pattern to transfer and transfe…
kevin-fruitful Nov 30, 2022
dec84c5
Revert "fix: apply check-effects-interactions pattern to transfer and…
amarinkovic Nov 30, 2022
3bd06d8
fix: re-apply check-effects-interactions pattern to transfer and tran…
amarinkovic Nov 30, 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
12 changes: 12 additions & 0 deletions docs/facets/IAdminFacet.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,15 @@ Gets the System context ID.
| --- | --- |
|`System` | Identifier|
<br></br>
### isObjectTokenizable
Check if object can be tokenized
```solidity
function isObjectTokenizable(
bytes32 _objectId
) external returns (bool)
```
#### Arguments:
| Argument | Type | Description |
| --- | --- | --- |
|`_objectId` | bytes32 | ID of the object|
<br></br>
18 changes: 16 additions & 2 deletions docs/facets/IEntityFacet.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ Enable an entity to be tokenized
```solidity
function enableEntityTokenization(
bytes32 _entityId,
string _symbol
string _symbol,
string _name
) external
```
#### Arguments:
| Argument | Type | Description |
| --- | --- | --- |
|`_entityId` | bytes32 | ID of the entity
|`_symbol` | string | The symbol assigned to the entity token|
|`_symbol` | string | The symbol assigned to the entity token
|`_name` | string | The name assigned to the entity token|
<br></br>
### startTokenSale
Start token sale of `_amount` tokens for total price of `_totalPrice`
Expand All @@ -66,6 +68,18 @@ Entity tokens are minted when the sale is started
|`_amount` | uint256 | amount of entity tokens to put on sale
|`_totalPrice` | uint256 | total price of the tokens|
<br></br>
### isTokenWrapped
Check if an entity token is wrapped as ERC20
```solidity
function isTokenWrapped(
bytes32 _entityId
) external returns (bool)
```
#### Arguments:
| Argument | Type | Description |
| --- | --- | --- |
|`_entityId` | bytes32 | ID of the entity|
<br></br>
### updateEntity
Update entity metadata
```solidity
Expand Down
18 changes: 16 additions & 2 deletions docs/facets/ISystemFacet.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Get meta of given object.
```solidity
function getObjectMeta(
bytes32 _id
) external returns (bytes32 parent, bytes32 dataHash, bytes32 tokenSymbol)
) external returns (bytes32 parent, bytes32 dataHash, string tokenSymbol, string tokenName, address tokenWrapper)
```
#### Arguments:
| Argument | Type | Description |
Expand All @@ -69,5 +69,19 @@ Get meta of given object.
| --- | --- |
|`parent` | object parent
|`dataHash` | object data hash
|`tokenSymbol` | object token symbol|
|`tokenSymbol` | object token symbol
|`tokenName` | object token name
|`tokenWrapper` | object token ERC20 wrapper address|
<br></br>
### wrapToken
Wrap an object token as ERC20
```solidity
function wrapToken(
bytes32 _objectId
) external
```
#### Arguments:
| Argument | Type | Description |
| --- | --- | --- |
|`_objectId` | bytes32 | ID of the tokenized object|
<br></br>
21 changes: 19 additions & 2 deletions docs/facets/ITokenizedVaultFacet.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ Total supply of platform asset
| --- | --- |
|`current` | balance|
<br></br>
### internalTransfer
### internalTransferFromEntity
Internal transfer of `amount` tokens
Transfer tokens internally
```solidity
function internalTransfer(
function internalTransferFromEntity(
bytes32 to,
bytes32 tokenId
) external
Expand All @@ -73,6 +73,23 @@ Transfer tokens internally
|`to` | bytes32 | token receiver
|`tokenId` | bytes32 | Internal ID of the token|
<br></br>
### wrapperInternalTransferFrom
Internal transfer of `amount` tokens `from` -> `to`
Transfer tokens internally between two IDs
```solidity
function wrapperInternalTransferFrom(
bytes32 from,
bytes32 to,
bytes32 tokenId
) external
```
#### Arguments:
| Argument | Type | Description |
| --- | --- | --- |
|`from` | bytes32 | token sender
|`to` | bytes32 | token receiver
|`tokenId` | bytes32 | Internal ID of the token|
<br></br>
### internalBurn
No description
```solidity
Expand Down
4 changes: 3 additions & 1 deletion src/diamonds/nayms/AppStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ struct AppStorage {
mapping(bytes32 => bool) existingObjects; // objectId => is an object?
mapping(bytes32 => bytes32) objectParent; // objectId => parentId
mapping(bytes32 => bytes32) objectDataHashes;
mapping(bytes32 => bytes32) objectTokenSymbol;
mapping(bytes32 => string) objectTokenSymbol;
mapping(bytes32 => string) objectTokenName;
mapping(bytes32 => address) objectTokenWrapper;
mapping(bytes32 => bool) existingEntities; // entityId => is an entity?
mapping(bytes32 => bool) existingSimplePolicies; // simplePolicyId => is a simple policy?
//// ENTITY ////
Expand Down
6 changes: 6 additions & 0 deletions src/diamonds/nayms/Modifiers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,10 @@ contract Modifiers {
require(LibACL._isInGroup(_objectId, _contextId, _group), "not in group");
_;
}

modifier assertERC20Wrapper(bytes32 _tokenId) {
(, , , , address erc20Wrapper) = LibObject._getObjectMeta(_tokenId);
require(msg.sender == erc20Wrapper, "only wrapper calls allowed");
_;
}
}
4 changes: 4 additions & 0 deletions src/diamonds/nayms/facets/AdminFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,8 @@ contract AdminFacet is Modifiers {
function getSystemId() external pure returns (bytes32) {
return LibAdmin._getSystemId();
}

function isObjectTokenizable(bytes32 _objectId) external view returns (bool) {
return LibObject._isObjectTokenizable(_objectId);
}
}
17 changes: 15 additions & 2 deletions src/diamonds/nayms/facets/EntityFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,14 @@ contract EntityFacet is Modifiers, ReentrancyGuard {
* @notice Enable an entity to be tokenized
* @param _objectId ID of the entity
* @param _symbol The symbol assigned to the entity token
* @param _name The name assigned to the entity token
*/
function enableEntityTokenization(bytes32 _objectId, string memory _symbol) external assertSysAdmin {
LibObject._enableObjectTokenization(_objectId, _symbol);
function enableEntityTokenization(
bytes32 _objectId,
string memory _symbol,
string memory _name
) external assertSysAdmin {
LibObject._enableObjectTokenization(_objectId, _symbol, _name);
}

/**
Expand All @@ -70,6 +75,14 @@ contract EntityFacet is Modifiers, ReentrancyGuard {
LibEntity._startTokenSale(_entityId, _amount, _totalPrice);
}

/**
* @notice Check if an entity token is wrapped as ERC20
* @param _entityId ID of the entity
*/
function isTokenWrapped(bytes32 _entityId) external view returns (bool) {
return LibObject._isObjectTokenWrapped(_entityId);
}

/**
* @notice Update entity metadata
* @param _entityId ID of the entity
Expand Down
17 changes: 15 additions & 2 deletions src/diamonds/nayms/facets/SystemFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import { LibHelpers } from "../libs/LibHelpers.sol";
import { LibObject } from "../libs/LibObject.sol";
import { LibACL } from "../libs/LibACL.sol";
import { LibEntity } from "../libs/LibEntity.sol";
import { ReentrancyGuard } from "../../../utils/ReentrancyGuard.sol";

/**
* @title System
* @notice Use it to perform system level operations
* @dev Use it to perform system level operations
*/
contract SystemFacet is Modifiers {
contract SystemFacet is Modifiers, ReentrancyGuard {
/**
* @notice Create an entity
* @dev An entity can be created with a zero max capacity! This is in the event where an entity cannot write any policies.
Expand Down Expand Up @@ -56,16 +57,28 @@ contract SystemFacet is Modifiers {
* @return parent object parent
* @return dataHash object data hash
* @return tokenSymbol object token symbol
* @return tokenName object token name
* @return tokenWrapper object token ERC20 wrapper address
*/
function getObjectMeta(bytes32 _id)
external
view
returns (
bytes32 parent,
bytes32 dataHash,
bytes32 tokenSymbol
string memory tokenSymbol,
string memory tokenName,
address tokenWrapper
)
{
return LibObject._getObjectMeta(_id);
}

/**
* @notice Wrap an object token as ERC20
* @param _objectId ID of the tokenized object
*/
function wrapToken(bytes32 _objectId) external nonReentrant assertSysMgr {
LibObject._wrapToken(_objectId);
}
}
27 changes: 21 additions & 6 deletions src/diamonds/nayms/facets/TokenizedVaultFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { LibHelpers } from "../libs/LibHelpers.sol";
import { LibTokenizedVault } from "../libs/LibTokenizedVault.sol";
import { LibObject } from "../libs/LibObject.sol";
import { LibEntity } from "../libs/LibEntity.sol";
import { ReentrancyGuard } from "../../../utils/ReentrancyGuard.sol";

/**
* @title Token Vault
Expand All @@ -15,7 +16,7 @@ import { LibEntity } from "../libs/LibEntity.sol";
* @dev Adaptation of ERC-1155 that uses AppStorage and aligns with Nayms ACL implementation.
* https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155
*/
contract TokenizedVaultFacet is Modifiers {
contract TokenizedVaultFacet is Modifiers, ReentrancyGuard {
/**
* @notice Gets balance of an account within platform
* @dev Internal balance for given account
Expand Down Expand Up @@ -43,18 +44,32 @@ contract TokenizedVaultFacet is Modifiers {
* @param to token receiver
* @param tokenId Internal ID of the token
*/
function internalTransfer(
function internalTransferFromEntity(
bytes32 to,
bytes32 tokenId,
uint256 amount
) external assertEntityAdmin(LibObject._getParent(LibHelpers._getSenderId())) {
// require(LibTokenizedVault._internalBalanceOf(senderId, tokenId) >= amount, "internalTransfer: insufficient balance");
bytes32 senderId = LibHelpers._getIdForAddress(msg.sender);
bytes32 senderEntityId = LibObject._getParent(senderId);
) external nonReentrant assertEntityAdmin(LibObject._getParentFromAddress(msg.sender)) {
bytes32 senderEntityId = LibObject._getParentFromAddress(msg.sender);
require(LibHelpers._stringToBytes32(LibConstants.STM_IDENTIFIER) != tokenId, "internalTransfer: can't transfer internal veNAYM");
LibTokenizedVault._internalTransfer(senderEntityId, to, tokenId, amount);
}

/**
* @notice Internal transfer of `amount` tokens `from` -> `to`
* @dev Transfer tokens internally between two IDs
* @param from token sender
* @param to token receiver
* @param tokenId Internal ID of the token
*/
function wrapperInternalTransferFrom(
bytes32 from,
bytes32 to,
bytes32 tokenId,
uint256 amount
) external nonReentrant assertERC20Wrapper(tokenId) {
LibTokenizedVault._internalTransfer(from, to, tokenId, amount);
}

function internalBurn(
bytes32 from,
bytes32 tokenId,
Expand Down
6 changes: 6 additions & 0 deletions src/diamonds/nayms/interfaces/IAdminFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,10 @@ interface IAdminFacet {
* @return System Identifier
*/
function getSystemId() external pure returns (bytes32);

/**
* @notice Check if object can be tokenized
* @param _objectId ID of the object
*/
function isObjectTokenizable(bytes32 _objectId) external returns (bool);
}
13 changes: 12 additions & 1 deletion src/diamonds/nayms/interfaces/IEntityFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,13 @@ interface IEntityFacet {
* @notice Enable an entity to be tokenized
* @param _entityId ID of the entity
* @param _symbol The symbol assigned to the entity token
* @param _name The name assigned to the entity token
*/
function enableEntityTokenization(bytes32 _entityId, string memory _symbol) external;
function enableEntityTokenization(
bytes32 _entityId,
string memory _symbol,
string memory _name
) external;

/**
* @notice Start token sale of `_amount` tokens for total price of `_totalPrice`
Expand All @@ -53,6 +58,12 @@ interface IEntityFacet {
uint256 _totalPrice
) external;

/**
* @notice Check if an entity token is wrapped as ERC20
* @param _entityId ID of the entity
*/
function isTokenWrapped(bytes32 _entityId) external view returns (bool);

/**
* @notice Update entity metadata
* @param _entityId ID of the entity
Expand Down
12 changes: 11 additions & 1 deletion src/diamonds/nayms/interfaces/ISystemFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,23 @@ interface ISystemFacet {
* @return parent object parent
* @return dataHash object data hash
* @return tokenSymbol object token symbol
* @return tokenName object token name
* @return tokenWrapper object token ERC20 wrapper address
*/
function getObjectMeta(bytes32 _id)
external
view
returns (
bytes32 parent,
bytes32 dataHash,
bytes32 tokenSymbol
string memory tokenSymbol,
string memory tokenName,
address tokenWrapper
);

/**
* @notice Wrap an object token as ERC20
* @param _objectId ID of the tokenized object
*/
function wrapToken(bytes32 _objectId) external;
}
16 changes: 15 additions & 1 deletion src/diamonds/nayms/interfaces/ITokenizedVaultFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,21 @@ interface ITokenizedVaultFacet {
* @param to token receiver
* @param tokenId Internal ID of the token
*/
function internalTransfer(
function internalTransferFromEntity(
bytes32 to,
bytes32 tokenId,
uint256 amount
) external;

/**
* @notice Internal transfer of `amount` tokens `from` -> `to`
* @dev Transfer tokens internally between two IDs
* @param from token sender
* @param to token receiver
* @param tokenId Internal ID of the token
*/
function wrapperInternalTransferFrom(
bytes32 from,
bytes32 to,
bytes32 tokenId,
uint256 amount
Expand Down
5 changes: 3 additions & 2 deletions src/diamonds/nayms/libs/LibEntity.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ library LibEntity {
event EntityCreated(bytes32 entityId, bytes32 entityAdmin);
event EntityUpdated(bytes32 entityId);
event SimplePolicyCreated(bytes32 indexed id, bytes32 entityId);
event TokenSaleStarted(bytes32 indexed entityId, uint256 offerId);
event TokenSaleStarted(bytes32 indexed entityId, uint256 offerId, string tokenSymbol, string tokenName);

/**
* @dev If an entity passes their checks to create a policy, ensure that the entity's capacity is appropriately decreased by the amount of capital that will be tied to the new policy being created.
Expand Down Expand Up @@ -123,6 +123,7 @@ library LibEntity {
) internal {
require(_amount > 0, "mint amount must be > 0");
require(_totalPrice > 0, "total price must be > 0");
require(LibObject._isObjectTokenizable(_entityId), "must be tokenizable");

AppStorage storage s = LibAppStorage.diamondStorage();
Entity memory entity = s.entities[_entityId];
Expand All @@ -131,7 +132,7 @@ library LibEntity {

(uint256 offerId, , ) = LibMarket._executeLimitOffer(_entityId, _entityId, _amount, entity.assetId, _totalPrice, LibConstants.FEE_SCHEDULE_STANDARD);

emit TokenSaleStarted(_entityId, offerId);
emit TokenSaleStarted(_entityId, offerId, s.objectTokenSymbol[_entityId], s.objectTokenName[_entityId]);
}

function _createEntity(
Expand Down
Loading