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

IPN-21 remove concept of "sales cycle" IPTs #159

Merged
Prev Previous commit
Next Next commit
full mainnet fork test case for new Tokenizer
Signed-off-by: stadolf <stefan@molecule.to>
  • Loading branch information
elmariachi111 committed Jul 5, 2024
commit 653474af8f2e188e17ab3166b248160908846fd7
181 changes: 144 additions & 37 deletions test/Forking/Tokenizer13UpgradeForkTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@ pragma solidity ^0.8.18;
import "forge-std/Test.sol";
import { console } from "forge-std/console.sol";

//import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

import { IPNFT } from "../../src/IPNFT.sol";

import { MustOwnIpnft, AlreadyTokenized, Tokenizer } from "../../src/Tokenizer.sol";
import { Tokenizer12 } from "../../src/helpers/test-upgrades/Tokenizer12.sol";
import { IPToken12, OnlyIssuerOrOwner } from "../../src/helpers/test-upgrades/IPToken12.sol";
import { IPToken, TokenCapped, Metadata } from "../../src/IPToken.sol";
import { IPermissioner, BlindPermissioner } from "../../src/Permissioner.sol";

// an error thrown by IPToken before 1.3
//error OnlyIssuerOrOwner();

contract Tokenizer13UpgradeForkTest is Test {
using SafeERC20Upgradeable for IPToken;

Expand All @@ -32,71 +29,93 @@ contract Tokenizer13UpgradeForkTest is Test {
address mainnetTokenizer = 0x58EB89C69CB389DBef0c130C6296ee271b82f436;
address mainnetIPNFT = 0xcaD88677CA87a7815728C72D74B4ff4982d54Fc1;

// old IP Token implementation
address vitaFASTAddress = 0x6034e0d6999741f07cb6Fb1162cBAA46a1D33d36;

// https://app.safe.global/home?safe=eth:0xf7990CD398daFB4fe5Fd6B9228B8e6f72b296555
address vitaFASTMultisig = 0xf7990CD398daFB4fe5Fd6B9228B8e6f72b296555;
address vitaDaoTreasury = 0xF5307a74d1550739ef81c6488DC5C7a6a53e5Ac2;

// paulhaas.eth
address paulhaas = 0x45602BFBA960277bF917C1b2007D1f03d7bd29e4;

// ValleyDAO multisig
address valleyDaoMultisig = 0xD920E60b798A2F5a8332799d8a23075c9E77d5F8;

// ValleyDAO IPNFT
uint256 valleyDaoIpnftId = 3;
IPNFT ipnft = IPNFT(mainnetIPNFT);
Tokenizer tokenizer13;
IPToken newIPTokenImplementation;

address alice = makeAddr("alice");

function setUp() public {
mainnetFork = vm.createFork(vm.envString("MAINNET_RPC_URL"), 18968463);
mainnetFork = vm.createFork(vm.envString("MAINNET_RPC_URL"), 20240430);
vm.selectFork(mainnetFork);
}

function testCanUpgradeToV13() public {
IPNFT ipnftMainnetInstance = IPNFT(mainnetIPNFT);
Tokenizer12 tokenizer12 = Tokenizer12(mainnetTokenizer);

function upgradeToTokenizer13() public {
vm.startPrank(mainnetDeployer);
Tokenizer newTokenizerImplementation = new Tokenizer();
IPToken newIPTokenImplementation = new IPToken();
newIPTokenImplementation = new IPToken();
vm.stopPrank();

vm.startPrank(mainnetOwner);
bytes memory upgradeCallData = abi.encodeWithSelector(Tokenizer.reinit.selector, address(newIPTokenImplementation));
Tokenizer12 tokenizer12 = Tokenizer12(mainnetTokenizer);
//todo: make sure that the legacy IPTs are indexed now
bytes memory upgradeCallData = abi.encodeWithSelector(Tokenizer.reinit.selector, address(newIPTokenImplementation));
tokenizer12.upgradeToAndCall(address(newTokenizerImplementation), upgradeCallData);
Tokenizer upgradedTokenizer = Tokenizer(mainnetTokenizer);

assertEq(address(upgradedTokenizer.ipTokenImplementation()), address(newIPTokenImplementation));
tokenizer13 = Tokenizer(mainnetTokenizer);
}

deployCodeTo("Permissioner.sol:BlindPermissioner", "", address(upgradedTokenizer.permissioner()));
vm.stopPrank();
function testCanUpgradeToV13() public {
upgradeToTokenizer13();
assertEq(address(tokenizer13.ipTokenImplementation()), address(newIPTokenImplementation));
assertEq(address(tokenizer13.permissioner()), 0xC837E02982992B701A1B5e4E21fA01cEB0a628fA);

vm.startPrank(alice);
vm.expectRevert("Initializable: contract is already initialized");
newTokenizerImplementation.initialize(IPNFT(address(0)), BlindPermissioner(address(0)));
tokenizer13.initialize(IPNFT(address(0)), BlindPermissioner(address(0)));

vm.expectRevert("Initializable: contract is already initialized");
newIPTokenImplementation.initialize(2, "Foo", "Bar", alice, "abcde");
vm.stopPrank();

vm.startPrank(mainnetOwner);
vm.expectRevert("Initializable: contract is already initialized");
upgradedTokenizer.initialize(IPNFT(address(0)), BlindPermissioner(address(0)));
tokenizer13.initialize(IPNFT(address(0)), BlindPermissioner(address(0)));

vm.expectRevert("Initializable: contract is already initialized");
upgradedTokenizer.reinit(IPToken(address(0)));
vm.stopPrank();
tokenizer13.reinit(newIPTokenImplementation);
}

function testOldIPTsAreMigratedAndCantBeReminted() public {
upgradeToTokenizer13();

assertEq(address(tokenizer13.synthesized(2)), 0x6034e0d6999741f07cb6Fb1162cBAA46a1D33d36);
assertEq(address(tokenizer13.synthesized(28)), 0x7b66E84Be78772a3afAF5ba8c1993a1B5D05F9C2);
assertEq(address(tokenizer13.synthesized(37)), 0xBcE56276591128047313e64744b3EBE03998783f);
assertEq(address(tokenizer13.synthesized(31415269)), address(0));

deployCodeTo("Permissioner.sol:BlindPermissioner", "", address(tokenizer13.permissioner()));

address vitaFASTMultisig = 0xf7990CD398daFB4fe5Fd6B9228B8e6f72b296555;

assertEq(ipnftMainnetInstance.ownerOf(valleyDaoIpnftId), valleyDaoMultisig);
vm.startPrank(vitaFASTMultisig);
vm.expectRevert(AlreadyTokenized.selector);
tokenizer13.tokenizeIpnft(2, 1_000_000 ether, "VITA-FAST", "bafkreig274nfj7srmtnb5wd5wlwm3ig2s63wovlz7i3noodjlfz2tm3n5q", bytes(""));

vm.startPrank(alice);
vm.expectRevert(MustOwnIpnft.selector);
tokenizer13.tokenizeIpnft(2, 1_000_000 ether, "VITA-FAST", "bafkreig274nfj7srmtnb5wd5wlwm3ig2s63wovlz7i3noodjlfz2tm3n5q", bytes(""));
}

function testTokenizeNewIPTs() public {
upgradeToTokenizer13();
address valleyDaoMultisig = 0xD920E60b798A2F5a8332799d8a23075c9E77d5F8;
uint256 valleyDaoIpnftId = 3; //hasnt been tokenized yet
deployCodeTo("Permissioner.sol:BlindPermissioner", "", address(tokenizer13.permissioner()));

assertEq(ipnft.ownerOf(valleyDaoIpnftId), valleyDaoMultisig);

vm.startPrank(valleyDaoMultisig);
IPToken ipt = upgradedTokenizer.tokenizeIpnft(valleyDaoIpnftId, 1_000_000 ether, "IPT", agreementCid, "");
IPToken ipt = tokenizer13.tokenizeIpnft(valleyDaoIpnftId, 1_000_000 ether, "VALLEY", agreementCid, "");
assertEq(ipt.balanceOf(valleyDaoMultisig), 1_000_000 ether);
ipt.transfer(alice, 100_000 ether);

assertEq(ipt.balanceOf(valleyDaoMultisig), 900_000 ether);
assertEq(ipt.balanceOf(alice), 100_000 ether);

//controlling the IPT from its own interface
ipt.issue(valleyDaoMultisig, 1_000_000 ether);
assertEq(ipt.totalSupply(), 2_000_000 ether);
assertEq(ipt.balanceOf(valleyDaoMultisig), 1_900_000 ether);
Expand All @@ -107,6 +126,12 @@ contract Tokenizer13UpgradeForkTest is Test {
ipt.issue(valleyDaoMultisig, 100);

vm.stopPrank();
}

function testOldTokensAreStillControllable() public {
upgradeToTokenizer13();
address vitaFASTAddress = 0x6034e0d6999741f07cb6Fb1162cBAA46a1D33d36;
address vitaFASTMultisig = 0xf7990CD398daFB4fe5Fd6B9228B8e6f72b296555;

IPToken vitaFast = IPToken(vitaFASTAddress);

Expand All @@ -120,12 +145,94 @@ contract Tokenizer13UpgradeForkTest is Test {
vm.stopPrank();

vm.startPrank(vitaFASTMultisig);
assertEq(vitaFast.balanceOf(vitaFASTMultisig), 16940676213630533216614);
assertEq(vitaFast.totalSupply(), 1_029_555 ether);
assertEq(vitaFast.balanceOf(vitaFASTMultisig), 13390539642731621592709);
//the old IPTs allow their original owner to issue more tokens
vitaFast.issue(vitaFASTMultisig, 100_000 ether);
assertEq(vitaFast.totalSupply(), 1129555 ether);
assertEq(vitaFast.balanceOf(vitaFASTMultisig), 116940676213630533216614);
assertEq(vitaFast.totalSupply(), 1_129_555 ether);
assertEq(vitaFast.balanceOf(vitaFASTMultisig), 113390539642731621592709);

vitaFast.cap();
vm.expectRevert(TokenCapped.selector);
vitaFast.issue(vitaFASTMultisig, 100_000 ether);

/// --- same for VitaRNA, better safe than sorry.
address vitaRNAAddress = 0x7b66E84Be78772a3afAF5ba8c1993a1B5D05F9C2;
address vitaRNAMultisig = 0x452f3b60129FdB3cdc78178848c63eC23f38C80d;
IPToken vitaRna = IPToken(vitaRNAAddress);

assertEq(vitaRna.balanceOf(paulhaas), 514.411456805927582924 ether);
assertEq(vitaRna.balanceOf(alice), 0);

vm.startPrank(paulhaas);
vitaRna.transfer(alice, 100 ether);
assertEq(vitaRna.balanceOf(paulhaas), 414.411456805927582924 ether);
assertEq(vitaRna.balanceOf(alice), 100 ether);
vm.stopPrank();

vm.startPrank(vitaRNAMultisig);
assertEq(vitaRna.totalSupply(), 5_000_000 ether);
assertEq(vitaRna.balanceOf(vitaRNAMultisig), 200_000 ether);
vitaRna.issue(vitaRNAMultisig, 100_000 ether);
assertEq(vitaRna.totalSupply(), 5_100_000 ether);
assertEq(vitaRna.balanceOf(vitaRNAMultisig), 300_000 ether);

vitaRna.cap();
vm.expectRevert(TokenCapped.selector);
vitaRna.issue(vitaRNAMultisig, 100_000 ether);
}

// IPN-21: and the main reason why we're doing all the above
function testOldTokensCanBeIssuedByNewIPNFTHolder() public {
upgradeToTokenizer13();

deployCodeTo("Permissioner.sol:BlindPermissioner", "", address(tokenizer13.permissioner()));

address bob = makeAddr("bob");
address vitaFASTMultisig = 0xf7990CD398daFB4fe5Fd6B9228B8e6f72b296555;
//we're using vita fast's original abi here. It actually is call-compatible to IPToken, but this is the ultimate legacy test
IPToken12 vitaFAST12 = IPToken12(0x6034e0d6999741f07cb6Fb1162cBAA46a1D33d36);
IPToken vitaFAST13 = IPToken(0x6034e0d6999741f07cb6Fb1162cBAA46a1D33d36);

vm.startPrank(vitaFASTMultisig);
ipnft.transferFrom(vitaFASTMultisig, alice, 2);
assertEq(ipnft.ownerOf(2), alice);

vm.startPrank(alice);
// This is new: originally Alice *would* indeed have been able to do this:
vm.expectRevert(AlreadyTokenized.selector);
tokenizer13.tokenizeIpnft(2, 1_000_000 ether, "VITA-FAST", "imfeelingfunny", bytes(""));

assertEq(vitaFAST12.balanceOf(alice), 0);

//this *should* be possible but can't work due to the old implementation
vm.expectRevert(OnlyIssuerOrOwner.selector);
vitaFAST12.issue(alice, 1_000_000 ether);
//the selector of course doesnt exist on the new interface, but the implementation reverts with it:
vm.expectRevert(OnlyIssuerOrOwner.selector);
vitaFAST13.issue(alice, 1_000_000 ether);

//to issue new tokens, alice uses the Tokenizer instead:
tokenizer13.issue(vitaFAST13, 1_000_000 ether, alice);
assertEq(vitaFAST12.balanceOf(alice), 1_000_000 ether);

//due to the original implementation, the original owner can still issue tokens and we cannot do anything about it:
vm.startPrank(vitaFASTMultisig);
vitaFAST12.issue(bob, 1_000_000 ether);
assertEq(vitaFAST12.balanceOf(bob), 1_000_000 ether);
assertEq(vitaFAST13.balanceOf(bob), 1_000_000 ether);

// but they cannot do that using the tokenizer:
vm.expectRevert(MustOwnIpnft.selector);
tokenizer13.issue(vitaFAST13, 1_000_000 ether, alice);
vm.expectRevert(MustOwnIpnft.selector);
tokenizer13.cap(vitaFAST13);

//but they unfortunately also can cap the token:
vitaFAST12.cap();

vm.startPrank(alice);
vm.expectRevert(TokenCapped.selector);
tokenizer13.issue(vitaFAST13, 1_000_000 ether, alice);
}
}