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/mega #262

Merged
merged 25 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b4b4ca1
feat: add toBytes8
clemlak Mar 2, 2023
6d3aa1d
feat: update encodeClaim and decodeClaim
clemlak Mar 2, 2023
05c606a
feat: add test_decodeClaim
clemlak Mar 2, 2023
f5baabc
feat: add utils encoder
clemlak Mar 2, 2023
beff891
feat: update encodeSwap, decodeSwap
clemlak Mar 2, 2023
7537712
test: update all swap related tests
clemlak Mar 2, 2023
7783f94
test: remove unused comments
clemlak Mar 2, 2023
f2d5391
test: remove encode funcs in test target contract
clemlak Mar 6, 2023
b4b81ae
test: add testFuzz_decodeCreatePair
clemlak Mar 6, 2023
3e85fcb
test: add test_decodeCreatePair_RevertIfBadLength
clemlak Mar 6, 2023
9c9cafe
test: add testFuzz_encodeCreatePool
clemlak Mar 6, 2023
9f22c9d
feat: use RLE for encodeCreatePool
clemlak Mar 7, 2023
d8e9e94
test: update encodeAllocate to use RLE
clemlak Mar 7, 2023
3ef3acc
test: add encodeAllocate calls
clemlak Mar 7, 2023
0069901
feat: update encodeAllocate, encodeDealloacate
clemlak Mar 7, 2023
239d30a
test: update encodeDeallocate calls
clemlak Mar 7, 2023
07b1222
test: add testFuzz_encodeDeallocate
clemlak Mar 7, 2023
a062ff4
test: add testFuzz_encodePoolId
clemlak Mar 7, 2023
62b10a2
test: add testFuzz_isBetween
clemlak Mar 7, 2023
e3350af
chore: add toBytes8 NatSpec
clemlak Mar 7, 2023
bc98eea
test: add testFuzz_addSignedDelta
clemlak Mar 7, 2023
c9883a6
test: add testFuzz_separate
clemlak Mar 7, 2023
4fdbf2c
chore: small NatSpac addition
clemlak Mar 7, 2023
3285d22
test: fix testFuzz_separate fuzzing
clemlak Mar 7, 2023
e43cd65
test: commenting out broken tests
clemlak Mar 7, 2023
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
12 changes: 12 additions & 0 deletions contracts/libraries/AssemblyLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ library AssemblyLib {
}
}

/**
* @dev There's no explict casting from dynamic to fixed sized bytes, this function
* handles it for us.
*/
function toBytes8(bytes memory raw) internal pure returns (bytes8 data) {
assembly {
data := mload(add(raw, 32))
let shift := mul(sub(8, mload(raw)), 8)
data := shr(shift, data)
}
}

/**
* @dev Safely casts an unsigned 128-bit integer into a signed 128-bit integer.
* Reverts on overflow.
Expand Down
120 changes: 85 additions & 35 deletions contracts/libraries/FVMLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -137,28 +137,43 @@ function decodeCreatePair(bytes calldata data) pure returns (address tokenAsset,
}

/**
* @dev Encodes a claim operation
* +--------------------------------------------------------------------+
* | Description | CLAIM | poolId | power0 | amount0 | power1 | amount1 |
* +--------------------------------------------------------------------+
* | Size (byte) | 1 | 8 | 1 | 16 | 1 | 16 |
* +--------------------------------------------------------------------+
* | Index | 0 | 1 - 9 | 9 | 10 - 26 | 26 | 27 - 43 |
* +--------------------------------------------------------------------+
* @dev Encodes a claim operation.
*
* FIXME: This function is not optimized! Using `encodePacked` is not ideal
* because it preserves all the trailing zeros for each type.
* An improved version should be made to reduce the calldata size.
*/
function encodeClaim(uint64 poolId, uint128 fee0, uint128 fee1) pure returns (bytes memory data) {
(uint8 powerFee0, uint128 baseFee0) = AssemblyLib.fromAmount(fee0);
(uint8 powerFee1, uint128 baseFee1) = AssemblyLib.fromAmount(fee1);

return abi.encodePacked(CLAIM, poolId, powerFee0, baseFee0, powerFee1, baseFee1);
return abi.encodePacked(
CLAIM,
uint8(10), // pointer to pointer1
poolId,
uint8(28), // pointer to fee1
powerFee0,
baseFee0,
powerFee1,
baseFee1
);
}

/**
* @dev Decodes a claim operation
*/
function decodeClaim(bytes calldata data) pure returns (uint64 poolId, uint128 fee0, uint128 fee1) {
poolId = uint64(bytes8(data[1:9]));
fee0 = AssemblyLib.toAmount(data[9:26]);
fee1 = AssemblyLib.toAmount(data[26:43]);
uint8 pointer0 = uint8(bytes1(data[1]));
poolId = uint64(AssemblyLib.toBytes8(data[2:pointer0]));
uint8 pointer1 = uint8(bytes1(data[pointer0]));
fee0 = AssemblyLib.toAmount(data[pointer0 + 1:pointer1]);
fee1 = AssemblyLib.toAmount(data[pointer1:data.length]);
}

/**
* @dev Encodes a create pool operation.
* FIXME: Same issue as `encodeClaim`... This function is not optimized!
*/
function encodeCreatePool(
uint24 pairId,
address controller,
Expand All @@ -170,7 +185,24 @@ function encodeCreatePool(
uint128 maxPrice,
uint128 price
) pure returns (bytes memory data) {
data = abi.encodePacked(CREATE_POOL, pairId, controller, priorityFee, fee, vol, dur, jit, maxPrice, price);
(uint8 power0, uint128 base0) = AssemblyLib.fromAmount(maxPrice);
(uint8 power1, uint128 base1) = AssemblyLib.fromAmount(price);

data = abi.encodePacked(
CREATE_POOL,
pairId,
controller,
priorityFee,
fee,
vol,
dur,
jit,
uint8(52),
power0,
base0,
power1,
base1
);
}

function decodeCreatePool(bytes calldata data)
Expand All @@ -187,20 +219,26 @@ function decodeCreatePool(bytes calldata data)
uint128 price
)
{
if (data.length != 66) revert InvalidBytesLength(66, data.length);
// if (data.length != 66) revert InvalidBytesLength(66, data.length);
pairId = uint24(bytes3(data[1:4]));
controller = address(bytes20(data[4:24]));
priorityFee = uint16(bytes2(data[24:26]));
fee = uint16(bytes2(data[26:28]));
vol = uint16(bytes2(data[28:30]));
dur = uint16(bytes2(data[30:32]));
jit = uint16(bytes2(data[32:34]));
maxPrice = uint128(bytes16(data[34:50]));
price = uint128(bytes16(data[50:]));
uint8 pointer0 = uint8(bytes1(data[34]));
maxPrice = AssemblyLib.toAmount(data[35:pointer0]);
price = AssemblyLib.toAmount(data[pointer0:]);
}

function encodeAllocate(uint8 useMax, uint64 poolId, uint8 power, uint128 amount) pure returns (bytes memory data) {
data = abi.encodePacked(AssemblyLib.pack(bytes1(useMax), ALLOCATE), poolId, power, amount);
/**
* @dev Encodes a allocate operation.
* FIXME: Same issue as `encodeClaim`... This function is not optimized!
*/
function encodeAllocate(uint8 useMax, uint64 poolId, uint128 deltaLiquidity) pure returns (bytes memory data) {
(uint8 power, uint128 base) = AssemblyLib.fromAmount(deltaLiquidity);
data = abi.encodePacked(AssemblyLib.pack(bytes1(useMax), ALLOCATE), poolId, power, base);
}

function decodeAllocate(bytes calldata data) pure returns (uint8 useMax, uint64 poolId, uint128 deltaLiquidity) {
Expand All @@ -211,46 +249,58 @@ function decodeAllocate(bytes calldata data) pure returns (uint8 useMax, uint64
deltaLiquidity = AssemblyLib.toAmount(data[9:]);
}

function encodeDeallocate(uint8 useMax, uint64 poolId, uint8 power, uint128 amount) pure returns (bytes memory data) {
data = abi.encodePacked(AssemblyLib.pack(bytes1(useMax), DEALLOCATE), poolId, power, amount);

function encodeDeallocate(uint8 useMax, uint64 poolId, uint128 deltaLiquidity) pure returns (bytes memory data) {
(uint8 power, uint128 base) = AssemblyLib.fromAmount(deltaLiquidity);
data = abi.encodePacked(AssemblyLib.pack(bytes1(useMax), DEALLOCATE), poolId, power, base);
}

function decodeDeallocate(bytes calldata data) pure returns (uint8 useMax, uint64 poolId, uint128 deltaLiquidity) {
if (data.length < 9) revert InvalidBytesLength(9, data.length);
useMax = uint8(data[0] >> 4);
poolId = uint64(bytes8(data[1:9]));
deltaLiquidity = uint128(AssemblyLib.toAmount(data[9:]));
deltaLiquidity = AssemblyLib.toAmount(data[9:]);
}

/**
* @dev Encodes a swap operation
* +-------------------------------------------------------------------------------+
* | Description | SWAP | poolId | power0 | amount0 | power1 | amount1 | sellAsset |
* +-------------+------+--------+--------+---------+--------+---------+-----------+
* | Size (byte) | 1 | 8 | 1 | 16 | 1 | 16 | 1 |
* +-------------+------+--------+--------+---------+--------+---------+-----------+
* | Index | 0 | 1 - 9 | 9 | 10 - 26 | 26 | 27 - 43 | 43 |
* +-------------------------------------------------------------------------------+
* FIXME: Same issue as `encodeClaim`... This function is not optimized!
*/
function encodeSwap(
uint8 useMax,
uint64 poolId,
uint8 power0,
uint128 amount0,
uint8 power1,
uint128 amount1,
uint8 sellAsset
) pure returns (bytes memory data) {
data = abi.encodePacked(AssemblyLib.pack(bytes1(useMax), SWAP), poolId, power0, amount0, power1, amount1, sellAsset);
(uint8 power0, uint128 base0) = AssemblyLib.fromAmount(amount0);
(uint8 power1, uint128 base1) = AssemblyLib.fromAmount(amount1);

data = abi.encodePacked(
AssemblyLib.pack(bytes1(useMax), SWAP),
sellAsset,
uint8(11), // pointer to pointer1
poolId,
uint8(29),
power0,
base0,
power1,
base1
);
}

/**
* @dev Decodes a swap operation.
*/
function decodeSwap(bytes calldata data)
pure
returns (uint8 useMax, uint64 poolId, uint128 input, uint128 output, uint8 sellAsset)
{
useMax = uint8(data[0] >> 4);
poolId = uint64(bytes8(data[1:9]));
input = AssemblyLib.toAmount(data[9:26]);
output = AssemblyLib.toAmount(data[26:43]);
sellAsset = uint8(data[data.length - 1]);
sellAsset = uint8(data[1]);
uint8 pointer0 = uint8(data[2]);
poolId = uint64(AssemblyLib.toBytes8(data[3:pointer0]));
uint8 pointer1 = uint8(data[pointer0]);
input = AssemblyLib.toAmount(data[pointer0 + 1:pointer1]);
output = AssemblyLib.toAmount(data[pointer1:data.length]);
}
58 changes: 58 additions & 0 deletions encoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
function toHex(input) {
return input.toString(16).length % 2 == 0 ? input.toString(16) : `0${input.toString(16)}`;
}

function fromAmount(amount) {
let power = 0;

while (amount % 10n == 0) {
amount /= 10n;
++power;
}

console.log(amount, power);

return `${toHex(power)}${toHex(amount)}`;
}

function encodeClaim(poolId, fee0, fee1) {
let data = '';

let encodedPoolId = toHex(poolId);
let encodedFee0 = fromAmount(fee0);
let encodedFee1 = fromAmount(fee1);

data += toHex(16);
data += toHex((data.length + encodedPoolId.length) / 2 + 1);
data += encodedPoolId;
data += toHex((data.length + encodedFee0.length) / 2 + 1);
data += encodedFee0;
data += encodedFee1;

return data;
}

function encodeSwap(
useMax,
sellAsset,
poolId,
amount0,
amount1,
) {
let data = '';

let encodedPoolId = toHex(poolId);
let encodedAmount0 = fromAmount(amount0);
let encodedAmount1 = fromAmount(amount1);

data += useMax ? '1' : '0';
data += '5';
data += sellAsset ? '01' : '00';
data += toHex((data.length + encodedPoolId.length) / 2 + 1);
data += encodedPoolId;
data += toHex((data.length + encodedAmount0.length) / 2 + 1);
data += encodedAmount0;
data += encodedAmount1;

return data;
}
8 changes: 4 additions & 4 deletions test/Setup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -226,19 +226,19 @@ contract Setup is Test {
}

modifier allocateSome(uint128 amt) {
subject().multiprocess(FVMLib.encodeAllocate(uint8(0), ghost().poolId, 0x0, amt));
subject().multiprocess(FVMLib.encodeAllocate(uint8(0), ghost().poolId, amt));
_;
}

modifier deallocateSome(uint128 amt) {
subject().multiprocess(FVMLib.encodeDeallocate(uint8(0), ghost().poolId, 0x0, amt));
subject().multiprocess(FVMLib.encodeDeallocate(uint8(0), ghost().poolId, amt));
_;
}

modifier swapSome(uint128 amt, bool sellAsset) {
uint128 amtOut = subject().getAmountOut(ghost().poolId, sellAsset, amt).safeCastTo128();
subject().multiprocess(
FVM.encodeSwap(uint8(0), ghost().poolId, 0x0, amt, 0x0, amtOut, uint8(sellAsset ? 1 : 0))
FVM.encodeSwap(uint8(0), ghost().poolId, amt, amtOut, uint8(sellAsset ? 1 : 0))
);
_;
}
Expand All @@ -250,7 +250,7 @@ contract Setup is Test {
: amtOut - uint256(-amtOutDelta).safeCastTo128();

subject().multiprocess(
FVM.encodeSwap(uint8(0), ghost().poolId, 0x0, amt, 0x0, amtOut, uint8(sellAsset ? 1 : 0))
FVM.encodeSwap(uint8(0), ghost().poolId, amt, amtOut, uint8(sellAsset ? 1 : 0))
);
_;
}
Expand Down
31 changes: 31 additions & 0 deletions test/TestAssemblyLib.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,35 @@ contract TestAssemblyLib is Test {
assertEq(base, 5);
}
}

/*
FIXME: These tests are not working yet.

function testFuzz_isBetween(uint256 value, uint256 lower, uint256 upper) public {
vm.assume(lower <= upper);
bool valid = AssemblyLib.isBetween(value, lower, upper);

if (lower >= value && value <= upper) {
assertTrue(valid);
} else {
assertFalse(valid);
}
}

function testFuzz_addSignedDelta(uint128 input, int128 delta) public {
assertEq(
AssemblyLib.addSignedDelta(input, delta),
delta < 0 ? uint128(-delta) : uint128(delta)
);
}
*/

function testFuzz_separate(uint8 a, uint8 b) public {
vm.assume(a <= 15);
vm.assume(b <= 15);
bytes1 data = AssemblyLib.pack(bytes1(a), bytes1(b));
(bytes1 a_, bytes1 b_) = AssemblyLib.separate(data);
assertEq(a, uint8(a_));
assertEq(b, uint8(b_));
}
}
Loading