Skip to content

Commit

Permalink
feat: Add price field to AddTranche (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
NunoAlexandre committed Jan 31, 2023
1 parent 2d91780 commit afb740c
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 37 deletions.
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

0 comments on commit afb740c

Please sign in to comment.