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

fix: LegacyDec transactions #3868

Open
wants to merge 12 commits into
base: stage
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 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
12 changes: 11 additions & 1 deletion .github/workflows/jest-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@ jobs:
matrix:
node-version: [20.x]
package:
["web", "utils", "server", "stores", "pools", "math", "bridge", "tx"]
[
"web",
"utils",
"server",
"stores",
"pools",
"math",
"bridge",
"tx",
"proto-codecs",
]

steps:
- name: Checkout Repo
Expand Down
25 changes: 25 additions & 0 deletions packages/proto-codecs/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = {
preset: "ts-jest",
roots: ["<rootDir>/src/", "<rootDir>/scripts/"],
testMatch: ["**/__tests__/?(*.)+(spec|test).[jt]s?(x)"],
testTimeout: 100000,
moduleNameMapper: {
"^(\\.{1,2}/.*)\\.js$": "$1",
},
transform: {
"^.+\\.(js|jsx)?$": [
"babel-jest",
{ configFile: "../../babel.config.json" },
],
"^.+\\.(ts|tsx)?$": [
"ts-jest",
{
useESM: true,
},
],
},
watchPlugins: [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname",
],
};
5 changes: 3 additions & 2 deletions packages/proto-codecs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"clean": "rm -rf node_modules; rm -rf build; rm -f tsconfig.tsbuildinfo",
"build": "tsc",
"dev": "tsc --watch",
"test:regression": "jest --passWithNoTests --runInBand",
"test": "jest",
"lint": "eslint \"src/**/*\" && prettier --check \"src/**/*\"",
"lint:fix": "eslint --fix \"src/**/*\" && prettier --write \"src/**/*\"",
"pre-commit": "lint-staged",
Expand All @@ -43,10 +43,11 @@
},
"devDependencies": {
"@cosmology/proto-parser": "^1.5.0",
"@cosmology/telescope": "^1.8.4",
"@cosmology/telescope": "^1.10.0",
"@types/node": "^20.14.1",
"regenerator-runtime": "^0.13.11",
"rimraf": "^5.0.0",
"ts-jest": "^29.1.2",
"tsx": "^4.6.2"
},
"dependencies": {
Expand Down
54 changes: 54 additions & 0 deletions packages/proto-codecs/scripts/__tests__/decimal-patch.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// decimal.test.ts
import { Decimal as CodegenDecimal } from "../../src/codegen/decimals";
import { Decimal as DecimalPatch } from "../decimals-patch";

/**
* Run the tests for both the codegen and the patch
* to ensure that the patch is correctly applied.
*/
[DecimalPatch, CodegenDecimal].forEach((Decimal) => {
test("should create a Decimal from user input", () => {
const decimal = Decimal.fromUserInput("123.456", 3);
expect(decimal.atomics).toBe("123456");
expect(decimal.fractionalDigits).toBe(3);
});

test("should throw an error for invalid user input", () => {
expect(() => Decimal.fromUserInput("123.45.6", 3)).toThrow(
"More than one separator found"
);
expect(() => Decimal.fromUserInput("123a.456", 3)).toThrow(
"Invalid character at position 4"
);
expect(() => Decimal.fromUserInput("123.4567", 3)).toThrow(
"Got more fractional digits than supported"
);
});

test("should create a Decimal from atomics", () => {
const decimal = Decimal.fromAtomics("123456", 3);
expect(decimal.atomics).toBe("123456");
expect(decimal.fractionalDigits).toBe(3);
});

test("should convert Decimal to string", () => {
const decimal = Decimal.fromUserInput("123.456", 3);
expect(decimal.toString()).toBe("123456");

const decimalNoFraction = Decimal.fromUserInput("123", 3);
expect(decimalNoFraction.toString()).toBe("123000");
});

test("should handle edge cases", () => {
const decimal = Decimal.fromUserInput("0.000", 3);
expect(decimal.toString()).toBe("0");

const decimalMaxFraction = Decimal.fromUserInput("1.999", 3);
expect(decimalMaxFraction.toString()).toBe("1999");
});

test("testing fractions", () => {
const decimal = Decimal.fromUserInput("0.01", 18);
expect(decimal.toString()).toBe("10000000000000000");
});
});
26 changes: 17 additions & 9 deletions packages/proto-codecs/scripts/codegen.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* eslint-disable import/no-extraneous-dependencies */
import * as fs from "node:fs";

import { ProtoStore } from "@cosmology/proto-parser";
import telescope from "@cosmology/telescope";
import { join } from "path";
Expand Down Expand Up @@ -69,9 +71,6 @@ telescope({
decode: true,
fromPartial: true,

// toSDK: true,
// fromSDK: true,

toAmino: true,
fromAmino: true,
fromProto: true,
Expand All @@ -88,17 +87,12 @@ telescope({
num64: "bigint",
customTypes: {
useCosmosSDKDec: true,
usePatchedDecimal: true,
},
},
},
aminoEncoding: {
enabled: true,
exceptions: {
// '/cosmos-sdk/MsgWithdrawValCommission': {
// aminoType: 'cosmos-sdk/MsgWithdrawValidatorCommission'
// },
},
// useRecursiveV2encoding: true,
},
interfaces: {
enabled: true,
Expand All @@ -113,6 +107,20 @@ telescope({
},
})
.then(() => {
/**
* Read the content of the decimals-patch.ts file and write it to
* the decimals.ts file in the codegen directory This is to patch
* the decimals.ts file to fix the Decimal class
*/
const decimalsPatchContent = fs.readFileSync(
join(__dirname, "./decimals-patch.ts"),
"utf8"
);
fs.writeFileSync(
join(__dirname, "../src/codegen/decimals.ts"),
decimalsPatchContent
);

console.info("✨ all done!");
})
.catch((e) => {
Expand Down
98 changes: 98 additions & 0 deletions packages/proto-codecs/scripts/decimals-patch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* This class patch is required to override Telescope number handling.
* Following Osmosis v26, which includes the new Cosmos SDK, we need to handle
* numbers in a different way. Specifically, we need to omit periods in the
* number representation to ensure compatibility with the updated SDK.
* This patch ensures that the Decimal class processes numbers correctly
* according to the new requirements.
*/

const maxFractionalDigits = 30;
export class Decimal {
public static fromUserInput(
input: string,
fractionalDigits: number
): Decimal {
Decimal.verifyFractionalDigits(fractionalDigits);
const badCharacter = input.match(/[^0-9.]/);
if (badCharacter) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
throw new Error(
`Invalid character at position ${badCharacter.index! + 1}`
);
}
let whole: string;
let fractional: string;
if (input === "") {
whole = "0";
fractional = "";
} else if (input.search(/\./) === -1) {
// integer format, no separator
whole = input;
fractional = "";
} else {
const parts = input.split(".");
switch (parts.length) {
case 0:
case 1:
throw new Error(
"Fewer than two elements in split result. This must not happen here."
);
case 2:
if (!parts[1]) throw new Error("Fractional part missing");
whole = parts[0];
fractional = parts[1].replace(/0+$/, "");
break;
default:
throw new Error("More than one separator found");
}
}
if (fractional.length > fractionalDigits) {
throw new Error("Got more fractional digits than supported");
}
const quantity = `${whole}${fractional.padEnd(fractionalDigits, "0")}`;
return new Decimal(quantity, fractionalDigits);
}
public static fromAtomics(
atomics: string,
fractionalDigits: number
): Decimal {
Decimal.verifyFractionalDigits(fractionalDigits);
return new Decimal(atomics, fractionalDigits);
}
private static verifyFractionalDigits(fractionalDigits: number): void {
if (!Number.isInteger(fractionalDigits))
throw new Error("Fractional digits is not an integer");
if (fractionalDigits < 0)
throw new Error("Fractional digits must not be negative");
if (fractionalDigits > maxFractionalDigits) {
throw new Error(
`Fractional digits must not exceed ${maxFractionalDigits}`
);
}
}
public get atomics(): string {
return this.data.atomics.toString();
}
public get fractionalDigits(): number {
return this.data.fractionalDigits;
}
private readonly data: {
readonly atomics: bigint;
readonly fractionalDigits: number;
};
private constructor(atomics: string, fractionalDigits: number) {
if (!atomics.match(/^[0-9]+$/)) {
throw new Error(
"Invalid string format. Only non-negative integers in decimal representation supported."
);
}
this.data = {
atomics: BigInt(atomics),
fractionalDigits: fractionalDigits,
};
}
public toString(): string {
return this.atomics;
}
JoseRFelix marked this conversation as resolved.
Show resolved Hide resolved
}
JoseRFelix marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion packages/proto-codecs/src/codegen/binary.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ts-nocheck
/**
* This file and any referenced files were automatically generated by @cosmology/telescope@1.8.4
* This file and any referenced files were automatically generated by @cosmology/telescope@1.10.0
* DO NOT MODIFY BY HAND. Instead, download the latest proto files for your chain
* and run the transpile command or npm scripts command that is used to regenerate this bundle.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//@ts-nocheck
import { Pubkey } from "@cosmjs/amino";
import { Decimal } from "@cosmjs/math";
import { decodePubkey, encodePubkey } from "@cosmjs/proto-signing";

import { BinaryReader, BinaryWriter } from "../../../binary";
import { Decimal } from "../../../decimals";
import {
Any,
AnyAmino,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//@ts-nocheck
import { Pubkey } from "@cosmjs/amino";
import { Decimal } from "@cosmjs/math";
import { decodePubkey, encodePubkey } from "@cosmjs/proto-signing";

import { BinaryReader, BinaryWriter } from "../../../binary";
import { Decimal } from "../../../decimals";
JoseRFelix marked this conversation as resolved.
Show resolved Hide resolved
import {
Any,
AnyAmino,
Expand Down
Loading
Loading