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

feat: Add price field to AddTranche #33

Merged
merged 5 commits into from
Jan 31, 2023
Merged
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
4 changes: 2 additions & 2 deletions src/Connector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,15 @@ contract CentrifugeConnector {
emit PoolAdded(poolId);
}

function addTranche(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol)
function addTranche(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price)
public
onlyRouter
{
Pool storage pool = pools[poolId];
require(pool.createdAt > 0, "CentrifugeConnector/invalid-pool");

Tranche storage tranche = tranches[poolId][trancheId];
tranche.latestPrice = 1*10**27;
tranche.latestPrice = uint256(price);
tranche.tokenName = tokenName;
tranche.tokenSymbol = tokenSymbol;

Expand Down
19 changes: 14 additions & 5 deletions src/Messages.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,35 @@ library ConnectorMessages {
*
* 0: call type (uint8 = 1 byte)
* 1-8: poolId (uint64 = 8 bytes)
* 9-25: trancheId (16 bytes)
* 26-154: tokenName (string = 128 bytes)
* 9-24: trancheId (16 bytes)
* 25-154: tokenName (string = 128 bytes)
* 155-187: tokenSymbol (string = 32 bytes)
* 185-200: price (uint128 = 16 bytes)
*/
function formatAddTranche(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol) internal pure returns (bytes memory) {
function formatAddTranche(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price) internal pure returns (bytes memory) {
// TODO(nuno): Now, we encode `tokenName` as a 128-bytearray by first encoding `tokenName`
// to bytes32 and then we encode three empty bytes32's, which sum up to a total of 128 bytes.
// Add support to actually encode `tokenName` fully as a 128 bytes string.
return abi.encodePacked(uint8(Call.AddTranche), poolId, trancheId, stringToBytes32(tokenName), bytes32(""), bytes32(""), bytes32(""), stringToBytes32(tokenSymbol));
return abi.encodePacked(
uint8(Call.AddTranche),
poolId,
trancheId,
stringToBytes32(tokenName), bytes32(""), bytes32(""), bytes32(""),
stringToBytes32(tokenSymbol),
price
);
}

function isAddTranche(bytes29 _msg) internal pure returns (bool) {
return messageType(_msg) == Call.AddTranche;
}

function parseAddTranche(bytes29 _msg) internal pure returns (uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol) {
function parseAddTranche(bytes29 _msg) internal pure returns (uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price) {
poolId = uint64(_msg.indexUint(1, 8));
trancheId = bytes16(_msg.index(9, 16));
tokenName = bytes32ToString(bytes32(_msg.index(25, 32)));
tokenSymbol = bytes32ToString(bytes32(_msg.index(153, 32)));
price = uint128(_msg.indexUint(185, 16));
}

// TODO: should be moved to a util contract
Expand Down
6 changes: 3 additions & 3 deletions src/routers/xcm/Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {ConnectorMessages} from "../../Messages.sol";

interface ConnectorLike {
function addPool(uint64 poolId) external;
function addTranche(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol) external;
function addTranche(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price) external;
function updateMember(uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) external;
function updateTokenPrice(uint64 poolId, bytes16 trancheId, uint256 price) external;
function handleTransfer(uint64 poolId, bytes16 trancheId, address user, uint256 amount) external;
Expand Down Expand Up @@ -47,8 +47,8 @@ contract ConnectorXCMRouter {
uint64 poolId = ConnectorMessages.parseAddPool(_msg);
connector.addPool(poolId);
} else if (ConnectorMessages.isAddTranche(_msg)) {
(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol) = ConnectorMessages.parseAddTranche(_msg);
connector.addTranche(poolId, trancheId, tokenName, tokenSymbol);
(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price) = ConnectorMessages.parseAddTranche(_msg);
connector.addTranche(poolId, trancheId, tokenName, tokenSymbol, price);
} else if (ConnectorMessages.isUpdateMember(_msg)) {
(uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) = ConnectorMessages.parseUpdateMember(_msg);
connector.updateMember(poolId, trancheId, user, validUntil);
Expand Down
29 changes: 15 additions & 14 deletions test/Connector.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,21 @@ contract ConnectorTest is Test {
bridgedConnector.addPool(poolId);
}

function testAddingSingleTrancheWorks(uint64 poolId, string memory tokenName, string memory tokenSymbol, bytes16 trancheId) public {
function testAddingSingleTrancheWorks(uint64 poolId, string memory tokenName, string memory tokenSymbol, bytes16 trancheId, uint128 price) public {
// 0. Add Pool
homeConnector.addPool(poolId);
(uint64 actualPoolId,) = bridgedConnector.pools(poolId);
assertEq(uint256(actualPoolId), uint256(poolId));

// 1. Add the tranche
homeConnector.addTranche(poolId, trancheId, tokenName, tokenSymbol);
homeConnector.addTranche(poolId, trancheId, tokenName, tokenSymbol, price);
// 2. Then deploy the tranche
bridgedConnector.deployTranche(poolId, trancheId);

(address token_, uint256 latestPrice,,string memory actualTokenName, string memory actualTokenSymbol)
= bridgedConnector.tranches(poolId, trancheId);
assertTrue(token_ != address(0));
assertTrue(latestPrice > 0);
assertEq(latestPrice, price);

// Comparing raw input to output can erroneously fail when a byte string is given.
// Intended behaviour is that byte strings will be treated as bytes and converted to strings
Expand All @@ -69,35 +69,36 @@ contract ConnectorTest is Test {
assertEq(token.symbol(), bytes32ToString(stringToBytes32(tokenSymbol)));
}

function testAddingMultipleTranchesWorks(uint64 poolId, bytes16[] calldata trancheIds, string memory tokenName, string memory tokenSymbol) public {
function testAddingMultipleTranchesWorks(uint64 poolId, bytes16[] calldata trancheIds, string memory tokenName, string memory tokenSymbol, uint128 price) public {
homeConnector.addPool(poolId);

for (uint i = 0; i < trancheIds.length; i++) {
homeConnector.addTranche(poolId, trancheIds[i], tokenName, tokenSymbol);
uint128 tranchePrice = price + uint128(i);
homeConnector.addTranche(poolId, trancheIds[i], tokenName, tokenSymbol, tranchePrice);
bridgedConnector.deployTranche(poolId, trancheIds[i]);
(address token, uint256 latestPrice, , ,) = bridgedConnector.tranches(poolId, trancheIds[i]);
assertTrue(latestPrice > 0);
assertEq(latestPrice, tranchePrice);
assertTrue(token != address(0));
}
}

function testAddingTranchesAsNonRouterFails(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol) public {
function testAddingTranchesAsNonRouterFails(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price) public {
homeConnector.addPool(poolId);
vm.expectRevert(bytes("CentrifugeConnector/not-the-router"));
bridgedConnector.addTranche(poolId, trancheId, tokenName, tokenSymbol);
bridgedConnector.addTranche(poolId, trancheId, tokenName, tokenSymbol, price);
}

function testAddingTranchesForNonExistentPoolFails(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol) public {
function testAddingTranchesForNonExistentPoolFails(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price) public {
vm.expectRevert(bytes("CentrifugeConnector/invalid-pool"));
homeConnector.addTranche(poolId, trancheId, tokenName, tokenSymbol);
homeConnector.addTranche(poolId, trancheId, tokenName, tokenSymbol, price);
}

function testUpdatingMemberWorks(uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) public {
vm.assume(validUntil >= safeAdd(block.timestamp, new Memberlist().minimumDelay()));
vm.assume(user != address(0));

homeConnector.addPool(poolId);
homeConnector.addTranche(poolId, trancheId, "Some Name", "SYMBOL");
homeConnector.addTranche(poolId, trancheId, "Some Name", "SYMBOL", 123);
bridgedConnector.deployTranche(poolId, trancheId);
homeConnector.updateMember(poolId, trancheId, user, validUntil);

Expand All @@ -114,7 +115,7 @@ contract ConnectorTest is Test {
vm.assume(user != address(0));

homeConnector.addPool(poolId);
homeConnector.addTranche(poolId, trancheId, "Some Name", "SYMBOL");
homeConnector.addTranche(poolId, trancheId, "Some Name", "SYMBOL", 123);
bridgedConnector.deployTranche(poolId, trancheId);
vm.expectRevert("invalid-validUntil");
homeConnector.updateMember(poolId, trancheId, user, validUntil);
Expand Down Expand Up @@ -147,7 +148,7 @@ contract ConnectorTest is Test {

function testUpdatingTokenPriceWorks(uint64 poolId, bytes16 trancheId, uint256 price) public {
homeConnector.addPool(poolId);
homeConnector.addTranche(poolId, trancheId, "Some Name", "SYMBOL");
homeConnector.addTranche(poolId, trancheId, "Some Name", "SYMBOL", 123);
homeConnector.updateTokenPrice(poolId, trancheId, price);

(, uint256 latestPrice, uint256 lastPriceUpdate, ,) = bridgedConnector.tranches(poolId, trancheId);
Expand All @@ -157,7 +158,7 @@ contract ConnectorTest is Test {

function testUpdatingTokenPriceAsNonRouterFails(uint64 poolId, bytes16 trancheId, uint256 price) public {
homeConnector.addPool(poolId);
homeConnector.addTranche(poolId, trancheId, "Some Name", "SYMBOL");
homeConnector.addTranche(poolId, trancheId, "Some Name", "SYMBOL", 123);
vm.expectRevert(bytes("CentrifugeConnector/not-the-router"));
bridgedConnector.updateTokenPrice(poolId, trancheId, price);
}
Expand Down
26 changes: 15 additions & 11 deletions test/Messages.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,37 +56,41 @@ contract MessagesTest is Test {

function testAddTrancheEncoding() public {
assertEq(
ConnectorMessages.formatAddTranche(0, toBytes16(fromHex("010000000000000064")), "Some Name", "SYMBOL"),
fromHex("02000000000000000000000000000000000000000000000009536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c0000000000000000000000000000000000000000000000000000")
ConnectorMessages.formatAddTranche(12378532, bytes16(hex"811acd5b3f17c06841c7e41e9e04cb1b"), "Some Name", "SYMBOL", 1),
hex"020000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c000000000000000000000000000000000000000000000000000000000000000000000000000000000001"
);
}

function testAddTrancheDecoding() public {
(uint64 decodedPoolId, bytes16 decodedTrancheId, string memory decodedTokenName, string memory decodedTokenSymbol) = ConnectorMessages.parseAddTranche(fromHex("02000000000000000000000000000000000000000000000009536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c0000000000000000000000000000000000000000000000000000").ref(0));
assertEq(uint(decodedPoolId), uint(0));
assertEq(decodedTrancheId, toBytes16(fromHex("010000000000000064")));
assertEq(decodedTokenName, "Some Name");
assertEq(decodedTokenSymbol, "SYMBOL");
(uint64 decodedPoolId, bytes16 decodedTrancheId, string memory decodedTokenName, string memory decodedTokenSymbol, uint256 decodedPrice) = ConnectorMessages.parseAddTranche(fromHex("020000000000bce1a4000000000000000000000000000000010505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505060606060606060606060606060606060606060606060606060606060606060600000000033b2e3c9fd0803ce8000000").ref(0));
assertEq(uint(decodedPoolId), uint(12378532));
assertEq(decodedTrancheId, bytes16(hex"00000000000000000000000000000001"));
assertEq(decodedTokenName, bytes32ToString(bytes32(hex"0505050505050505050505050505050505050505050505050505050505050505")));
assertEq(decodedTokenSymbol, bytes32ToString(hex"0606060606060606060606060606060606060606060606060606060606060606"));
assertEq(decodedPrice, uint(1000000000000000000000000000));
}

function testAddTrancheEquivalence(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol)
function testAddTrancheEquivalence(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price)
public
{
bytes memory _message = ConnectorMessages.formatAddTranche(
poolId,
trancheId,
tokenName,
tokenSymbol
tokenSymbol,
price
);
(uint64 decodedPoolId, bytes16 decodedTrancheId, string memory decodedTokenName, string memory decodedTokenSymbol) = ConnectorMessages
(uint64 decodedPoolId, bytes16 decodedTrancheId, string memory decodedTokenName, string memory decodedTokenSymbol, uint256 decodedPrice) = ConnectorMessages
.parseAddTranche(_message.ref(0));
assertEq(uint256(decodedPoolId), uint256(poolId));
assertEq(decodedTrancheId, trancheId);
// Comparing raw input to output can erroneously fail when a byte string is given.
// Comparing raw input to output can erroneously fail when a byte string is given.
// Intended behaviour is that byte strings will be treated as bytes and converted to strings instead of treated as strings themselves.
// This conversion from string to bytes32 to string is used to simulate this intended behaviour.
assertEq(decodedTokenName, bytes32ToString(stringToBytes32(tokenName)));
assertEq(decodedTokenSymbol, bytes32ToString(stringToBytes32(tokenSymbol)));
// TODO(nuno): fix this
assertEq(decodedPrice, uint256(price));
}

function testUpdateMemberEncoding() public {
Expand Down
4 changes: 2 additions & 2 deletions test/mock/MockHomeConnector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ contract MockHomeConnector is Test {
router.handle(_message);
}

function addTranche(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol) public {
bytes memory _message = ConnectorMessages.formatAddTranche(poolId, trancheId, tokenName, tokenSymbol);
function addTranche(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price) public {
bytes memory _message = ConnectorMessages.formatAddTranche(poolId, trancheId, tokenName, tokenSymbol, price);
router.handle(_message);
}

Expand Down