@exponent-labs/i80f48-util 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/build/i80f48.d.ts +8 -0
- package/build/i80f48.js +54 -0
- package/build/i80f48.js.map +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +18 -0
- package/build/index.js.map +1 -0
- package/jest.config.ts +10 -0
- package/package.json +23 -0
- package/src/i80f48.ts +56 -0
- package/src/index.ts +1 -0
- package/src/main.test.ts +16 -0
- package/tsconfig.json +17 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [0.0.3](https://github.com/exponent-finance/exponent-core/compare/@exponent-labs/i80f48-util@0.0.2...@exponent-labs/i80f48-util@0.0.3) (2025-03-03)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @exponent-labs/i80f48-util
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.0.2](https://github.com/exponent-finance/exponent-core/compare/@exponent-labs/i80f48-util@0.0.1...@exponent-labs/i80f48-util@0.0.2) (2025-03-03)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @exponent-labs/i80f48-util
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import BigNumber from "bignumber.js";
|
|
4
|
+
import { Buffer } from "buffer";
|
|
5
|
+
export declare function decodeBufferLE(buffer: Buffer): string;
|
|
6
|
+
export declare function toI80f48(bigNum: BigNumber): BigNumber;
|
|
7
|
+
export declare function encodeI80f48ToBufferLE(bigNum: BigNumber): Buffer;
|
|
8
|
+
export declare function stringToI80f48Buffer(input: string): Buffer;
|
package/build/i80f48.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.stringToI80f48Buffer = exports.encodeI80f48ToBufferLE = exports.toI80f48 = exports.decodeBufferLE = void 0;
|
|
7
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
8
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
9
|
+
const buffer_1 = require("buffer");
|
|
10
|
+
const FRACTIONAL_BITS = 48;
|
|
11
|
+
const FRACTIONAL_MASK = new bn_js_1.default("FFFFFFFFFFFF", 16); // Mask for the lowest 48 bits
|
|
12
|
+
function decodeBufferLE(buffer) {
|
|
13
|
+
const h = buffer.reverse().toString("hex");
|
|
14
|
+
const bn = new bn_js_1.default(h, 16);
|
|
15
|
+
const integerPart = bn.shrn(FRACTIONAL_BITS); // Shift right to get the integer part
|
|
16
|
+
const fractionalPart = bn.and(FRACTIONAL_MASK);
|
|
17
|
+
const fractionalDecimal = new bignumber_js_1.default(fractionalPart.toString(10)).div(new bignumber_js_1.default(2).pow(FRACTIONAL_BITS));
|
|
18
|
+
const result = new bignumber_js_1.default(integerPart.toString(10)).plus(fractionalDecimal);
|
|
19
|
+
return result.toString();
|
|
20
|
+
}
|
|
21
|
+
exports.decodeBufferLE = decodeBufferLE;
|
|
22
|
+
// Function to convert a BigNumber to i80f48
|
|
23
|
+
function toI80f48(bigNum) {
|
|
24
|
+
const BIT_SHIFT = 48;
|
|
25
|
+
// Shift the fractional part to the integer part
|
|
26
|
+
const shiftedNum = bigNum.multipliedBy(new bignumber_js_1.default(2).pow(BIT_SHIFT)).integerValue();
|
|
27
|
+
return shiftedNum;
|
|
28
|
+
}
|
|
29
|
+
exports.toI80f48 = toI80f48;
|
|
30
|
+
// Function to encode an i80f48 BigNumber to a 128-bit buffer in little-endian format
|
|
31
|
+
function encodeI80f48ToBufferLE(bigNum) {
|
|
32
|
+
// Convert to i80f48 format
|
|
33
|
+
const i80f48Num = toI80f48(bigNum);
|
|
34
|
+
// Create a buffer of 128 bits (16 bytes)
|
|
35
|
+
const buffer = buffer_1.Buffer.alloc(16);
|
|
36
|
+
// Split the BigNumber into two 64-bit parts
|
|
37
|
+
const high = i80f48Num.dividedToIntegerBy(new bignumber_js_1.default(2).pow(64));
|
|
38
|
+
const low = i80f48Num.mod(new bignumber_js_1.default(2).pow(64));
|
|
39
|
+
// Write the low part (64 bits) in little-endian order
|
|
40
|
+
buffer.writeBigUInt64LE(BigInt(low.toFixed()), 0);
|
|
41
|
+
// Write the high part (64 bits) in little-endian order
|
|
42
|
+
buffer.writeBigUInt64LE(BigInt(high.toFixed()), 8);
|
|
43
|
+
return buffer;
|
|
44
|
+
}
|
|
45
|
+
exports.encodeI80f48ToBufferLE = encodeI80f48ToBufferLE;
|
|
46
|
+
// Function to convert a string to an i80f48 buffer
|
|
47
|
+
function stringToI80f48Buffer(input) {
|
|
48
|
+
// Convert the string to a BigNumber
|
|
49
|
+
const bigNum = new bignumber_js_1.default(input);
|
|
50
|
+
// Encode the BigNumber to an i80f48 buffer
|
|
51
|
+
return encodeI80f48ToBufferLE(bigNum);
|
|
52
|
+
}
|
|
53
|
+
exports.stringToI80f48Buffer = stringToI80f48Buffer;
|
|
54
|
+
//# sourceMappingURL=i80f48.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i80f48.js","sourceRoot":"","sources":["../src/i80f48.ts"],"names":[],"mappings":";;;;;;AAAA,gEAAoC;AACpC,kDAAsB;AACtB,mCAA+B;AAE/B,MAAM,eAAe,GAAG,EAAE,CAAA;AAC1B,MAAM,eAAe,GAAG,IAAI,eAAE,CAAC,cAAc,EAAE,EAAE,CAAC,CAAA,CAAC,8BAA8B;AAEjF,SAAgB,cAAc,CAAC,MAAc;IAC3C,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC1C,MAAM,EAAE,GAAG,IAAI,eAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACxB,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA,CAAC,sCAAsC;IACnF,MAAM,cAAc,GAAG,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAC9C,MAAM,iBAAiB,GAAG,IAAI,sBAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,sBAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAA;IAC/G,MAAM,MAAM,GAAG,IAAI,sBAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IAE9E,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAA;AAC1B,CAAC;AATD,wCASC;AACD,4CAA4C;AAC5C,SAAgB,QAAQ,CAAC,MAAiB;IACxC,MAAM,SAAS,GAAG,EAAE,CAAA;IAEpB,gDAAgD;IAChD,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,sBAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,EAAE,CAAA;IAEtF,OAAO,UAAU,CAAA;AACnB,CAAC;AAPD,4BAOC;AAED,qFAAqF;AACrF,SAAgB,sBAAsB,CAAC,MAAiB;IACtD,2BAA2B;IAC3B,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;IAElC,yCAAyC;IACzC,MAAM,MAAM,GAAG,eAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAE/B,4CAA4C;IAC5C,MAAM,IAAI,GAAG,SAAS,CAAC,kBAAkB,CAAC,IAAI,sBAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IACnE,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,sBAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IAEnD,sDAAsD;IACtD,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAEjD,uDAAuD;IACvD,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAElD,OAAO,MAAM,CAAA;AACf,CAAC;AAlBD,wDAkBC;AAED,mDAAmD;AACnD,SAAgB,oBAAoB,CAAC,KAAa;IAChD,oCAAoC;IACpC,MAAM,MAAM,GAAG,IAAI,sBAAS,CAAC,KAAK,CAAC,CAAA;IAEnC,2CAA2C;IAC3C,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAA;AACvC,CAAC;AAND,oDAMC"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./i80f48";
|
package/build/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./i80f48"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAwB"}
|
package/jest.config.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// jest.config.ts
|
|
2
|
+
import type { Config } from "@jest/types"
|
|
3
|
+
|
|
4
|
+
const config: Config.InitialOptions = {
|
|
5
|
+
preset: "ts-jest",
|
|
6
|
+
testEnvironment: "node",
|
|
7
|
+
testMatch: ["**/*.test.ts"], // Adjust the pattern if your test files have a different naming convention
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default config
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@exponent-labs/i80f48-util",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"main": "build/index.js",
|
|
5
|
+
"types": "build/index.d.ts",
|
|
6
|
+
"license": "AGPL-3.0",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc --build",
|
|
9
|
+
"test": "jest"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"bignumber.js": "9.1.2",
|
|
13
|
+
"bn.js": "5.2.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/jest": "^29.5.12",
|
|
17
|
+
"jest": "^29.7.0",
|
|
18
|
+
"ts-jest": "^29.1.2",
|
|
19
|
+
"ts-node": "10.9.2",
|
|
20
|
+
"typescript": "5.4.5"
|
|
21
|
+
},
|
|
22
|
+
"gitHead": "209b8847e9a0fadb5b5ec96b9b47f0ace4a3bf9d"
|
|
23
|
+
}
|
package/src/i80f48.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js"
|
|
2
|
+
import BN from "bn.js"
|
|
3
|
+
import { Buffer } from "buffer"
|
|
4
|
+
|
|
5
|
+
const FRACTIONAL_BITS = 48
|
|
6
|
+
const FRACTIONAL_MASK = new BN("FFFFFFFFFFFF", 16) // Mask for the lowest 48 bits
|
|
7
|
+
|
|
8
|
+
export function decodeBufferLE(buffer: Buffer): string {
|
|
9
|
+
const h = buffer.reverse().toString("hex")
|
|
10
|
+
const bn = new BN(h, 16)
|
|
11
|
+
const integerPart = bn.shrn(FRACTIONAL_BITS) // Shift right to get the integer part
|
|
12
|
+
const fractionalPart = bn.and(FRACTIONAL_MASK)
|
|
13
|
+
const fractionalDecimal = new BigNumber(fractionalPart.toString(10)).div(new BigNumber(2).pow(FRACTIONAL_BITS))
|
|
14
|
+
const result = new BigNumber(integerPart.toString(10)).plus(fractionalDecimal)
|
|
15
|
+
|
|
16
|
+
return result.toString()
|
|
17
|
+
}
|
|
18
|
+
// Function to convert a BigNumber to i80f48
|
|
19
|
+
export function toI80f48(bigNum: BigNumber): BigNumber {
|
|
20
|
+
const BIT_SHIFT = 48
|
|
21
|
+
|
|
22
|
+
// Shift the fractional part to the integer part
|
|
23
|
+
const shiftedNum = bigNum.multipliedBy(new BigNumber(2).pow(BIT_SHIFT)).integerValue()
|
|
24
|
+
|
|
25
|
+
return shiftedNum
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Function to encode an i80f48 BigNumber to a 128-bit buffer in little-endian format
|
|
29
|
+
export function encodeI80f48ToBufferLE(bigNum: BigNumber): Buffer {
|
|
30
|
+
// Convert to i80f48 format
|
|
31
|
+
const i80f48Num = toI80f48(bigNum)
|
|
32
|
+
|
|
33
|
+
// Create a buffer of 128 bits (16 bytes)
|
|
34
|
+
const buffer = Buffer.alloc(16)
|
|
35
|
+
|
|
36
|
+
// Split the BigNumber into two 64-bit parts
|
|
37
|
+
const high = i80f48Num.dividedToIntegerBy(new BigNumber(2).pow(64))
|
|
38
|
+
const low = i80f48Num.mod(new BigNumber(2).pow(64))
|
|
39
|
+
|
|
40
|
+
// Write the low part (64 bits) in little-endian order
|
|
41
|
+
buffer.writeBigUInt64LE(BigInt(low.toFixed()), 0)
|
|
42
|
+
|
|
43
|
+
// Write the high part (64 bits) in little-endian order
|
|
44
|
+
buffer.writeBigUInt64LE(BigInt(high.toFixed()), 8)
|
|
45
|
+
|
|
46
|
+
return buffer
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Function to convert a string to an i80f48 buffer
|
|
50
|
+
export function stringToI80f48Buffer(input: string): Buffer {
|
|
51
|
+
// Convert the string to a BigNumber
|
|
52
|
+
const bigNum = new BigNumber(input)
|
|
53
|
+
|
|
54
|
+
// Encode the BigNumber to an i80f48 buffer
|
|
55
|
+
return encodeI80f48ToBufferLE(bigNum)
|
|
56
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./i80f48"
|
package/src/main.test.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { decodeBufferLE, stringToI80f48Buffer } from "./i80f48"
|
|
2
|
+
describe("i80f48-util", () => {
|
|
3
|
+
it("handles 0", () => {
|
|
4
|
+
const n = stringToI80f48Buffer("0")
|
|
5
|
+
expect(n.length).toEqual(16)
|
|
6
|
+
for (let i = 0; i < 16; i++) {
|
|
7
|
+
expect(n[i]).toEqual(0)
|
|
8
|
+
}
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it("handles rational numbers", () => {
|
|
12
|
+
const n = stringToI80f48Buffer("1.001")
|
|
13
|
+
const s = decodeBufferLE(n)
|
|
14
|
+
expect(parseFloat(s)).toBeCloseTo(1.001)
|
|
15
|
+
})
|
|
16
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"rootDir": "src",
|
|
4
|
+
"sourceMap": true,
|
|
5
|
+
"incremental": true /* Save .tsbuildinfo files to allow for incremental compilation of projects. */,
|
|
6
|
+
"composite": true /* Enable constraints that allow a TypeScript project to be used with project references. */,
|
|
7
|
+
"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
|
8
|
+
"module": "CommonJS" /* Specify what module code is generated. */,
|
|
9
|
+
"declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
|
|
10
|
+
"outDir": "./build" /* Specify an output folder for all emitted files. */,
|
|
11
|
+
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
|
12
|
+
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
|
13
|
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"],
|
|
16
|
+
"exclude": ["build", "node_modules", "**/*.test.ts"]
|
|
17
|
+
}
|