Skip to content

Commit

Permalink
Deterministic Deploys (#60)
Browse files Browse the repository at this point in the history
* WIP: Add some tests for deterministic deploys

* fix tranche token test

* rename token test files to .t.sol

* cross-chain test passing

* Add memberlist tests

* Add env vars

* Fix formatting

* Change to secret

* Fix syntax

* Assume destination address is not 0x0

* Format

* Update test/Connector.t.sol

Co-authored-by: Nuno Alexandre <[email protected]>

* Fix typo

---------

Co-authored-by: Jeroen Offerijns <[email protected]>
Co-authored-by: Jeroen Offerijns <[email protected]>
Co-authored-by: Nuno Alexandre <[email protected]>
  • Loading branch information
4 people authored Apr 30, 2023
1 parent c1fc9c1 commit 02af4b9
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 51 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
RPC_URL=
CENTRIFUGE_CHAIN_ORIGIN=0x7369626cef070000000000000000000000000000
MAINNET_RPC_URL=https://mainnet.infura.io/v3/...
POLYGON_RPC_URL=https://polygon-mainnet.infura.io/v3/...
PRIVATE_KEY=
ETHERSCAN_KEY=
5 changes: 4 additions & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ jobs:
id: test

env:
FOUNDRY_PROFILE: pull_request
FOUNDRY_PROFILE: push_to_main
CENTRIFUGE_CHAIN_ORIGIN: ${{ secrets.CENTRIFUGE_CHAIN_ORIGIN }}
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }}

lint:
name: fmt
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/push-to-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ jobs:
forge test -vvv
id: test
env:
FOUNDRY_PROFILE: push_to_main
FOUNDRY_PROFILE: push_to_main
CENTRIFUGE_CHAIN_ORIGIN: ${{ secrets.CENTRIFUGE_CHAIN_ORIGIN }}
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }}
48 changes: 0 additions & 48 deletions test/token/factory.sol

This file was deleted.

153 changes: 153 additions & 0 deletions test/token/factory.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.18;
pragma abicoder v2;

import {TrancheTokenFactory, MemberlistFactory} from "src/token/factory.sol";
import {RestrictedToken} from "src/token/restricted.sol";
import "forge-std/Test.sol";

contract FactoryTest is Test {
// address(0)[0:20] + keccak("Centrifuge")[21:32]
bytes32 SALT = 0x000000000000000000000000000000000000000075eb27011b69f002dc094d05;
uint256 mainnetFork;
uint256 polygonFork;

function setUp() public {
mainnetFork = vm.createFork(vm.envString("MAINNET_RPC_URL"));
polygonFork = vm.createFork(vm.envString("POLYGON_RPC_URL"));
}

function testTokenFactoryIsDeterministicAcrossChains(
address sender,
string memory name,
string memory symbol,
uint64 poolId,
bytes16 trancheId,
uint8 decimals
) public {
vm.selectFork(mainnetFork);
TrancheTokenFactory tokenFactory1 = new TrancheTokenFactory{ salt: SALT }();
address token1 = tokenFactory1.newTrancheToken(poolId, trancheId, name, symbol, decimals);

vm.selectFork(polygonFork);
TrancheTokenFactory tokenFactory2 = new TrancheTokenFactory{ salt: SALT }();
assertEq(address(tokenFactory1), address(tokenFactory2));
vm.prank(sender);
address token2 = tokenFactory2.newTrancheToken(poolId, trancheId, name, symbol, decimals);
assertEq(address(token1), address(token2));
}

function testTokenFactoryShouldBeDeterministic() public {
address predictedAddress = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
SALT,
keccak256(abi.encodePacked(type(TrancheTokenFactory).creationCode))
)
)
)
)
);
TrancheTokenFactory tokenFactory = new TrancheTokenFactory{ salt: SALT }();
assertEq(address(tokenFactory), predictedAddress);
}

function testTrancheTokenShouldBeDeterministic(
uint64 poolId,
bytes16 trancheId,
string memory name,
string memory symbol,
uint8 decimals
) public {
TrancheTokenFactory tokenFactory = new TrancheTokenFactory{ salt: SALT }();

bytes32 salt = keccak256(abi.encodePacked(poolId, trancheId));
address predictedAddress = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
address(tokenFactory),
salt,
keccak256(abi.encodePacked(type(RestrictedToken).creationCode, abi.encode(decimals)))
)
)
)
)
);

address token = tokenFactory.newTrancheToken(poolId, trancheId, name, symbol, decimals);

assertEq(address(token), predictedAddress);
}

function testDeployingDeterministicAddressTwiceReverts(
uint64 poolId,
bytes16 trancheId,
string memory name,
string memory symbol,
uint8 decimals
) public {
address predictedAddress = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
SALT,
keccak256(abi.encodePacked(type(TrancheTokenFactory).creationCode))
)
)
)
)
);
TrancheTokenFactory tokenFactory = new TrancheTokenFactory{ salt: SALT }();
assertEq(address(tokenFactory), predictedAddress);
address token1 = tokenFactory.newTrancheToken(poolId, trancheId, name, symbol, decimals);
vm.expectRevert();
address token2 = tokenFactory.newTrancheToken(poolId, trancheId, name, symbol, decimals);
}

function testMemberlistFactoryIsDeterministicAcrossChains(
address sender,
uint64 poolId,
bytes16 trancheId,
uint256 threshold
) public {
vm.selectFork(mainnetFork);
MemberlistFactory memberlistFactory1 = new MemberlistFactory{ salt: SALT }();
address memberlist1 = memberlistFactory1.newMemberlist();

vm.selectFork(polygonFork);
MemberlistFactory memberlistFactory2 = new MemberlistFactory{ salt: SALT }();
assertEq(address(memberlistFactory1), address(memberlistFactory2));
vm.prank(sender);
address memberlist2 = memberlistFactory2.newMemberlist();
assertEq(address(memberlist1), address(memberlist2));
}

function testMemberlistShouldBeDeterministic() public {
address predictedAddress = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
SALT,
keccak256(abi.encodePacked(type(MemberlistFactory).creationCode))
)
)
)
)
);
MemberlistFactory memberlistFactory = new MemberlistFactory{ salt: SALT }();
assertEq(address(memberlistFactory), predictedAddress);
}
}
File renamed without changes.

0 comments on commit 02af4b9

Please sign in to comment.