Skip to content

DES-32 Bring your own IPT: Tokenizer allows attaching arbitrary ERC20s #173

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

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ jobs:
- name: Install node dependencies
run: yarn --frozen-lockfile

#todo: forge build --sizes
- name: Run Forge build
run: |
forge --version
forge build --sizes
forge build
id: build

- name: Run Forge tests
Expand Down
100 changes: 0 additions & 100 deletions script/dev/Synthesizer.s.sol

This file was deleted.

5 changes: 4 additions & 1 deletion script/dev/Tokenizer.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import "forge-std/Script.sol";
import "forge-std/console.sol";
import { IPNFT } from "../../src/IPNFT.sol";
import { Tokenizer } from "../../src/Tokenizer.sol";
import { Metadata, IPToken } from "../../src/IPToken.sol";
import { Metadata } from "../../src/IIPToken.sol";
import { IPToken } from "../../src/IPToken.sol";

import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { IPermissioner, TermsAcceptedPermissioner } from "../../src/Permissioner.sol";
import { CommonScript } from "./Common.sol";
Expand Down Expand Up @@ -60,3 +62,4 @@ contract FixtureTokenizer is CommonScript {
console.log("IPTS_ADDRESS=%s", address(tokenContract));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ pragma solidity ^0.8.18;

import "forge-std/Script.sol";
import { Tokenizer } from "../../src/Tokenizer.sol";
import { IPToken } from "../../src/IPToken.sol";
import { WrappedIPToken } from "../../src/WrappedIPToken.sol";
import { console } from "forge-std/console.sol";

contract RolloutTokenizerV13 is Script {
contract RolloutTokenizerV14 is Script {
function run() public {
vm.startBroadcast();

IPToken newIpTokenImplementation = new IPToken();
WrappedIPToken wrappedIpTokenImplementation = new WrappedIPToken();
Tokenizer newTokenizerImplementation = new Tokenizer();

bytes memory upgradeCallData = abi.encodeWithSelector(Tokenizer.reinit.selector, address(newIpTokenImplementation));
bytes memory upgradeCallData = abi.encodeWithSelector(Tokenizer.reinit.selector, address(wrappedIpTokenImplementation));

console.log("NEWTOKENIMPLEMENTATION=%s", address(newIpTokenImplementation));
console.log("WRAPPEDTOKENIMPLEMENTATION=%s", address(wrappedIpTokenImplementation));
console.log("NEWTOKENIZER=%s", address(newTokenizerImplementation));
console.logBytes(upgradeCallData);

Expand Down
21 changes: 21 additions & 0 deletions src/IIPToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

struct Metadata {
uint256 ipnftId;
address originalOwner;
string agreementCid;
}

interface IIPToken {
/// @notice the amount of tokens that ever have been issued (not necessarily == supply)
function totalIssued() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function metadata() external view returns (Metadata memory);
function issue(address, uint256) external;
function cap() external;
function uri() external view returns (string memory);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
31 changes: 21 additions & 10 deletions src/IPToken.sol
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import { ERC20BurnableUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol";
import { Tokenizer, MustControlIpnft } from "./Tokenizer.sol";
import { IControlIPTs } from "./IControlIPTs.sol";

struct Metadata {
uint256 ipnftId;
address originalOwner;
string agreementCid;
}
import { IIPToken, Metadata } from "./IIPToken.sol";

error TokenCapped();

Expand All @@ -24,7 +20,7 @@ error TokenCapped();
* The owner can increase the token supply as long as it's not explicitly capped.
* @dev formerly known as "molecules"
*/
contract IPToken is ERC20BurnableUpgradeable, OwnableUpgradeable {
contract IPToken is IIPToken, ERC20Upgradeable, ERC20BurnableUpgradeable, OwnableUpgradeable {
event Capped(uint256 atSupply);

/// @notice the amount of tokens that ever have been issued (not necessarily == supply)
Expand All @@ -35,12 +31,12 @@ contract IPToken is ERC20BurnableUpgradeable, OwnableUpgradeable {

Metadata internal _metadata;

function initialize(uint256 ipnftId, string calldata name, string calldata symbol, address originalOwner, string memory agreementCid)
function initialize(uint256 ipnftId, string calldata name_, string calldata symbol_, address originalOwner, string memory agreementCid)
external
initializer
{
__Ownable_init();
__ERC20_init(name, symbol);
__ERC20_init(name_, symbol_);
_metadata = Metadata({ ipnftId: ipnftId, originalOwner: originalOwner, agreementCid: agreementCid });
}

Expand All @@ -59,6 +55,21 @@ contract IPToken is ERC20BurnableUpgradeable, OwnableUpgradeable {
return _metadata;
}

function balanceOf(address account) public view override(ERC20Upgradeable, IIPToken) returns (uint256) {
return ERC20Upgradeable.balanceOf(account);
}

function name() public view override(ERC20Upgradeable, IIPToken) returns (string memory) {
return ERC20Upgradeable.name();
}

function symbol() public view override(ERC20Upgradeable, IIPToken) returns (string memory) {
return ERC20Upgradeable.symbol();
}

function decimals() public view override(ERC20Upgradeable, IIPToken) returns (uint8) {
return ERC20Upgradeable.decimals();
}
/**
* @notice the supply of IP Tokens is controlled by the tokenizer contract.
* @param receiver address
Expand Down Expand Up @@ -109,7 +120,7 @@ contract IPToken is ERC20BurnableUpgradeable, OwnableUpgradeable {
string.concat(
'{"name": "IP Tokens of IPNFT #',
tokenId,
'","description": "IP Tokens, derived from IP-NFTs, are ERC-20 tokens governing IP pools.","decimals": 18,"external_url": "https://molecule.to","image": "",',
'","description": "IP Tokens, derived from IP-NFTs, are ERC-20 tokens governing IP pools.","decimals": 18,"external_url": "https://molecule.xyz","image": "",',
props,
"}"
)
Expand Down
14 changes: 7 additions & 7 deletions src/Permissioner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.8.18;
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import { IPToken, Metadata } from "./IPToken.sol";
import { IIPToken, Metadata } from "./IIPToken.sol";

error InvalidSignature();
error Denied();
Expand All @@ -16,17 +16,17 @@ interface IPermissioner {
* @param _for address
* @param data bytes
*/
function accept(IPToken tokenContract, address _for, bytes calldata data) external;
function accept(IIPToken tokenContract, address _for, bytes calldata data) external;
}

contract BlindPermissioner is IPermissioner {
function accept(IPToken tokenContract, address _for, bytes calldata data) external {
function accept(IIPToken tokenContract, address _for, bytes calldata data) external {
//empty
}
}

contract ForbidAllPermissioner is IPermissioner {
function accept(IPToken, address, bytes calldata) external pure {
function accept(IIPToken, address, bytes calldata) external pure {
revert Denied();
}
}
Expand All @@ -44,7 +44,7 @@ contract TermsAcceptedPermissioner is IPermissioner {
* @param _for address the account that has created `signature`
* @param signature bytes encoded signature, for eip155: `abi.encodePacked(r, s, v)`
*/
function accept(IPToken tokenContract, address _for, bytes calldata signature) external {
function accept(IIPToken tokenContract, address _for, bytes calldata signature) external {
if (!isValidSignature(tokenContract, _for, signature)) {
revert InvalidSignature();
}
Expand All @@ -55,7 +55,7 @@ contract TermsAcceptedPermissioner is IPermissioner {
* @notice checks whether `signer`'s `signature` of `specificTermsV1` on `tokenContract.metadata.ipnftId` is valid
* @param tokenContract IPToken
*/
function isValidSignature(IPToken tokenContract, address signer, bytes calldata signature) public view returns (bool) {
function isValidSignature(IIPToken tokenContract, address signer, bytes calldata signature) public view returns (bool) {
bytes32 termsHash = ECDSA.toEthSignedMessageHash(bytes(specificTermsV1(tokenContract)));
return SignatureChecker.isValidSignatureNow(signer, termsHash, signature);
}
Expand All @@ -78,7 +78,7 @@ contract TermsAcceptedPermissioner is IPermissioner {
* @notice this yields the message text that claimers must present to proof they have accepted all terms
* @param tokenContract IPToken
*/
function specificTermsV1(IPToken tokenContract) public view returns (string memory) {
function specificTermsV1(IIPToken tokenContract) public view returns (string memory) {
return (specificTermsV1(tokenContract.metadata()));
}
}
5 changes: 3 additions & 2 deletions src/SalesShareDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/O
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IPNFT } from "./IPNFT.sol";
import { IPToken, Metadata } from "./IPToken.sol";
import { Metadata } from "./IIPToken.sol";
import { IPToken } from "./IPToken.sol";
import { Tokenizer, MustControlIpnft } from "./Tokenizer.sol";
import { SchmackoSwap, ListingState } from "./SchmackoSwap.sol";
import { IPermissioner, TermsAcceptedPermissioner } from "./Permissioner.sol";
Expand Down Expand Up @@ -133,7 +134,7 @@ contract SalesShareDistributor is UUPSUpgradeable, OwnableUpgradeable, Reentranc
* Requires the originalOwner to behave honestly / in favor of the IPT holders
* Requires the caller to have approved `paidPrice` of `paymentToken` to this contract
*
* @param tokenContract IPToken the IPToken token contract
* @param tokenContract IIPToken the IPToken token contract
* @param paymentToken IERC20 the payment token contract address
* @param paidPrice uint256 the price the NFT has been sold for
* @param permissioner IPermissioner the permissioner that permits claims
Expand Down
Loading
Loading