mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-10 21:49:15 +00:00
Merge pull request #1554 from cosmos/parseCoins-ibc
Add IBC denom support to parseCoins from @cosmjs/amino
This commit is contained in:
commit
6c610331d4
13
CHANGELOG.md
13
CHANGELOG.md
@ -6,6 +6,19 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- @cosmjs/amino: Add IBC denom support to `parseCoins` and use the same
|
||||
implementation in all those imports:
|
||||
|
||||
```ts
|
||||
import { parseCoins } from "@cosmjs/proto-signing";
|
||||
// equals
|
||||
import { parseCoins } from "@cosmjs/stargate";
|
||||
// equals
|
||||
import { parseCoins } from "@cosmjs/amino";
|
||||
```
|
||||
|
||||
## [0.32.2] - 2023-12-19
|
||||
|
||||
### Fixed
|
||||
|
@ -81,15 +81,41 @@ describe("coins", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for two", () => {
|
||||
expect(parseCoins("819966000ucosm,700000000ustake")).toEqual([
|
||||
it("works for various denoms", () => {
|
||||
// very short (3)
|
||||
expect(parseCoins("7643bar")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
amount: "7643",
|
||||
denom: "bar",
|
||||
},
|
||||
]);
|
||||
|
||||
// very long (128)
|
||||
expect(
|
||||
parseCoins(
|
||||
"7643abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
amount: "7643",
|
||||
denom:
|
||||
"abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
|
||||
},
|
||||
]);
|
||||
|
||||
// IBC denom (https://github.com/cosmos/cosmos-sdk/blob/v0.42.7/types/coin_test.go#L512-L519)
|
||||
expect(parseCoins("7643ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2",
|
||||
},
|
||||
]);
|
||||
|
||||
// Token factory denom (https://docs.osmosis.zone/osmosis-core/modules/tokenfactory/)
|
||||
expect(parseCoins("100000000000factory/osmo1c584m4lq25h83yp6ag8hh4htjr92d954vklzja/ufoo")).toEqual([
|
||||
{
|
||||
amount: "100000000000",
|
||||
denom: "factory/osmo1c584m4lq25h83yp6ag8hh4htjr92d954vklzja/ufoo",
|
||||
},
|
||||
]);
|
||||
});
|
||||
@ -144,6 +170,19 @@ describe("coins", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for two", () => {
|
||||
expect(parseCoins("819966000ucosm,700000000ustake")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("ignores empty elements", () => {
|
||||
// start
|
||||
expect(parseCoins(",819966000ucosm,700000000ustake")).toEqual([
|
||||
@ -186,6 +225,20 @@ describe("coins", () => {
|
||||
|
||||
// amount missing
|
||||
expect(() => parseCoins("ucosm")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom starting with slash
|
||||
expect(() => parseCoins("3456/ibc")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom too short
|
||||
expect(() => parseCoins("3456a")).toThrowError(/invalid coin string/i);
|
||||
expect(() => parseCoins("3456aa")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom too long
|
||||
expect(() =>
|
||||
parseCoins(
|
||||
"3456abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgha",
|
||||
),
|
||||
).toThrowError(/invalid coin string/i);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -46,13 +46,21 @@ export function coins(amount: number | string, denom: string): Coin[] {
|
||||
/**
|
||||
* Takes a coins list like "819966000ucosm,700000000ustake" and parses it.
|
||||
*
|
||||
* A Stargate-ready variant of this function is available via:
|
||||
* Starting with CosmJS 0.32.3, the following imports are all synonym and support
|
||||
* a variety of denom types such as IBC denoms or tokenfactory. If you need to
|
||||
* restrict the denom to something very minimal, this needs to be implemented
|
||||
* separately in the caller.
|
||||
*
|
||||
* ```
|
||||
* import { parseCoins } from "@cosmjs/proto-signing";
|
||||
* // or
|
||||
* // equals
|
||||
* import { parseCoins } from "@cosmjs/stargate";
|
||||
* // equals
|
||||
* import { parseCoins } from "@cosmjs/amino";
|
||||
* ```
|
||||
*
|
||||
* This function is not made for supporting decimal amounts and does not support
|
||||
* parsing gas prices.
|
||||
*/
|
||||
export function parseCoins(input: string): Coin[] {
|
||||
return input
|
||||
@ -60,7 +68,8 @@ export function parseCoins(input: string): Coin[] {
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.map((part) => {
|
||||
const match = part.match(/^([0-9]+)([a-zA-Z]+)/);
|
||||
// Denom regex from Stargate (https://github.com/cosmos/cosmos-sdk/blob/v0.42.7/types/coin.go#L599-L601)
|
||||
const match = part.match(/^([0-9]+)([a-zA-Z][a-zA-Z0-9/]{2,127})$/);
|
||||
if (!match) throw new Error("Got an invalid coin string");
|
||||
return {
|
||||
amount: match[1].replace(/^0+/, "") || "0",
|
||||
|
@ -1,170 +0,0 @@
|
||||
import { parseCoins } from "./coins";
|
||||
|
||||
describe("coins", () => {
|
||||
describe("parseCoins", () => {
|
||||
it("works for empty", () => {
|
||||
expect(parseCoins("")).toEqual([]);
|
||||
});
|
||||
|
||||
it("works for one element", () => {
|
||||
expect(parseCoins("7643ureef")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for various denoms", () => {
|
||||
// very short (3)
|
||||
expect(parseCoins("7643bar")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "bar",
|
||||
},
|
||||
]);
|
||||
|
||||
// very long (128)
|
||||
expect(
|
||||
parseCoins(
|
||||
"7643abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom:
|
||||
"abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
|
||||
},
|
||||
]);
|
||||
|
||||
// IBC denom (https://github.com/cosmos/cosmos-sdk/blob/v0.42.7/types/coin_test.go#L512-L519)
|
||||
expect(parseCoins("7643ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("trims leading zeros", () => {
|
||||
expect(parseCoins("07643ureef")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
expect(parseCoins("007643ureef")).toEqual([
|
||||
{
|
||||
amount: "7643",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
expect(parseCoins("0ureef")).toEqual([
|
||||
{
|
||||
amount: "0",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
expect(parseCoins("0000ureef")).toEqual([
|
||||
{
|
||||
amount: "0",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for large numbers", () => {
|
||||
expect(parseCoins(`${Number.MAX_SAFE_INTEGER}ureef`)).toEqual([
|
||||
{
|
||||
amount: "9007199254740991",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
// 2**64-1
|
||||
expect(parseCoins("18446744073709551615ureef")).toEqual([
|
||||
{
|
||||
amount: "18446744073709551615",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
// 2**128-1
|
||||
expect(parseCoins("340282366920938463463374607431768211455ureef")).toEqual([
|
||||
{
|
||||
amount: "340282366920938463463374607431768211455",
|
||||
denom: "ureef",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("works for two", () => {
|
||||
expect(parseCoins("819966000ucosm,700000000ustake")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("ignores empty elements", () => {
|
||||
// start
|
||||
expect(parseCoins(",819966000ucosm,700000000ustake")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
// middle
|
||||
expect(parseCoins("819966000ucosm,,700000000ustake")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
// end
|
||||
expect(parseCoins("819966000ucosm,700000000ustake,")).toEqual([
|
||||
{
|
||||
amount: "819966000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
{
|
||||
amount: "700000000",
|
||||
denom: "ustake",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("throws for invalid inputs", () => {
|
||||
// denom missing
|
||||
expect(() => parseCoins("3456")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// amount missing
|
||||
expect(() => parseCoins("ucosm")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom starting with slash
|
||||
expect(() => parseCoins("3456/ibc")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom too short
|
||||
expect(() => parseCoins("3456a")).toThrowError(/invalid coin string/i);
|
||||
expect(() => parseCoins("3456aa")).toThrowError(/invalid coin string/i);
|
||||
|
||||
// denom too long
|
||||
expect(() =>
|
||||
parseCoins(
|
||||
"3456abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgha",
|
||||
),
|
||||
).toThrowError(/invalid coin string/i);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,23 +0,0 @@
|
||||
import { Coin } from "@cosmjs/amino";
|
||||
|
||||
/**
|
||||
* Takes a coins list like "819966000ucosm,700000000ustake" and parses it.
|
||||
*
|
||||
* This is a Stargate ready version of parseCoins from @cosmjs/amino.
|
||||
* It supports more denoms.
|
||||
*/
|
||||
export function parseCoins(input: string): Coin[] {
|
||||
return input
|
||||
.replace(/\s/g, "")
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.map((part) => {
|
||||
// Denom regex from Stargate (https://github.com/cosmos/cosmos-sdk/blob/v0.42.7/types/coin.go#L599-L601)
|
||||
const match = part.match(/^([0-9]+)([a-zA-Z][a-zA-Z0-9/]{2,127})$/);
|
||||
if (!match) throw new Error("Got an invalid coin string");
|
||||
return {
|
||||
amount: match[1].replace(/^0+/, "") || "0",
|
||||
denom: match[2],
|
||||
};
|
||||
});
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
// This type happens to be shared between Amino and Direct sign modes
|
||||
export { parseCoins } from "./coins";
|
||||
export { DecodedTxRaw, decodeTxRaw } from "./decode";
|
||||
export {
|
||||
DirectSecp256k1HdWallet,
|
||||
@ -31,4 +30,6 @@ export {
|
||||
} from "./signer";
|
||||
export { makeAuthInfoBytes, makeSignBytes, makeSignDoc } from "./signing";
|
||||
export { executeKdf, KdfConfiguration } from "./wallet";
|
||||
export { Coin, coin, coins } from "@cosmjs/amino";
|
||||
|
||||
// re-exports
|
||||
export { Coin, coin, coins, parseCoins } from "@cosmjs/amino";
|
||||
|
Loading…
x
Reference in New Issue
Block a user