Skip to content

Commit 716130f

Browse files
committed
fixed bug decimal number trx and display locked balance
1 parent 4ace908 commit 716130f

File tree

7 files changed

+238
-30
lines changed

7 files changed

+238
-30
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bitriel-wallet-sdk",
3-
"version": "1.1.14",
3+
"version": "1.1.15",
44
"description": "This is bitriel Wallet SDK",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",

src/sdk.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
TokenInfo,
66
TransactionRequest,
77
FeeEstimate,
8+
DetailedBalance,
89
} from "./wallet/types";
910
import { NetworkConfig, SUPPORTED_NETWORKS } from "./config/networks";
1011
import { SubstrateWalletProvider } from "./wallet/substrate";
@@ -101,16 +102,81 @@ export class BitrielWalletSDK {
101102
}
102103
}
103104

105+
// Get detailed balance information
106+
const detailedBalance = await this.getDetailedBalance();
107+
104108
return {
105109
address,
106110
balances: {
107111
native: nativeBalance,
108112
tokens: tokenBalances,
113+
detailed: detailedBalance,
109114
},
110115
network: this.currentNetwork,
111116
};
112117
}
113118

119+
/**
120+
* Get detailed balance information including locked and transferable balances
121+
* @returns Detailed balance information
122+
*/
123+
async getDetailedBalance(): Promise<DetailedBalance> {
124+
if (!this.currentNetwork) {
125+
throw new Error("No network connected");
126+
}
127+
128+
const provider = this.providers.get(
129+
this.currentNetwork.chainId.toString()
130+
);
131+
if (!provider) {
132+
throw new Error("Provider not found");
133+
}
134+
135+
const totalBalance = await provider.getBalance();
136+
const decimals = this.currentNetwork.nativeCurrency.decimals;
137+
138+
// For Substrate chains, we can get locked balance from the system account
139+
if (this.currentNetwork.type === "substrate") {
140+
const substrateProvider = provider as SubstrateWalletProvider;
141+
const accountInfo = await substrateProvider.getAccountInfo();
142+
// Calculate locked and transferable balances
143+
const locked = accountInfo.data.frozen.toString();
144+
const transferable = (
145+
BigInt(totalBalance) - BigInt(locked)
146+
).toString();
147+
148+
return {
149+
total: totalBalance,
150+
locked,
151+
transferable,
152+
formatted: {
153+
total: this.formatTokenBalance(totalBalance, decimals),
154+
locked: this.formatTokenBalance(locked, decimals),
155+
transferable: this.formatTokenBalance(
156+
transferable,
157+
decimals
158+
),
159+
},
160+
};
161+
} else {
162+
// For EVM chains, we don't have locked balances by default
163+
// This could be extended to support specific EVM chains that implement locking
164+
return {
165+
total: totalBalance,
166+
locked: "0",
167+
transferable: totalBalance,
168+
formatted: {
169+
total: this.formatTokenBalance(totalBalance, decimals),
170+
locked: "0.0",
171+
transferable: this.formatTokenBalance(
172+
totalBalance,
173+
decimals
174+
),
175+
},
176+
};
177+
}
178+
}
179+
114180
async sendTransaction(tx: TransactionRequest): Promise<string> {
115181
if (!this.currentNetwork) {
116182
throw new Error("No network connected");

src/utils/amount.ts

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,13 @@ export function parseTransactionAmount(
2121
if (chainType === "evm") {
2222
return ethers.parseEther(amount.toString()).toString();
2323
} else {
24-
return new BN(amount.toString())
25-
.mul(new BN(10).pow(new BN(decimals)))
26-
.toString();
27-
}
28-
}
29-
30-
/**
31-
* Formats amount for both Substrate and EVM chains
32-
* @param amount The amount in base units (as string)
33-
* @param chainType The type of chain ('substrate' or 'evm')
34-
* @param decimals Number of decimal places (default: 18)
35-
* @returns The human-readable amount as string
36-
*/
37-
export function formatTransactionAmount(
38-
amount: string,
39-
chainType: "substrate" | "evm",
40-
decimals: number = 18
41-
): string {
42-
if (chainType === "evm") {
43-
return ethers.formatEther(amount);
44-
} else {
45-
const bn = new BN(amount);
46-
const divisor = new BN(10).pow(new BN(decimals));
47-
const whole = bn.div(divisor).toString();
48-
const fraction = bn.mod(divisor).toString().padStart(decimals, "0");
49-
return `${whole}.${fraction}`;
24+
// For Substrate, we need to handle decimal numbers properly
25+
const amountStr = amount.toString();
26+
const [whole, fraction = ""] = amountStr.split(".");
27+
const paddedFraction = fraction
28+
.padEnd(decimals, "0")
29+
.slice(0, decimals);
30+
const fullNumber = whole + paddedFraction;
31+
return new BN(fullNumber).toString();
5032
}
5133
}

src/wallet/substrate.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ export class SubstrateWalletProvider implements WalletProvider {
8686
return accountInfo.data.free.toString();
8787
}
8888

89+
/**
90+
* Get detailed account information including locked balance
91+
* @returns Account information
92+
*/
93+
async getAccountInfo(): Promise<SubstrateAccountInfo> {
94+
if (!this.api || !this.pair) {
95+
throw new Error("Wallet not connected");
96+
}
97+
return (await this.api.query.system.account(
98+
this.pair.address
99+
)) as SubstrateAccountInfo;
100+
}
101+
89102
async sendTransaction(tx: PolkadotTransactionRequest): Promise<string> {
90103
if (!this.api || !this.pair) {
91104
throw new Error("Wallet not connected");

src/wallet/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,21 @@ export interface TokenBalance {
4242
formatted: string;
4343
}
4444

45+
export interface DetailedBalance {
46+
total: string;
47+
locked: string;
48+
transferable: string;
49+
formatted: {
50+
total: string;
51+
locked: string;
52+
transferable: string;
53+
};
54+
}
55+
4556
export interface WalletBalances {
4657
native: string;
4758
tokens: TokenBalance[];
59+
detailed?: DetailedBalance;
4860
}
4961

5062
export interface WalletState {
@@ -89,6 +101,9 @@ export interface SubstrateAccountInfo {
89101
free: {
90102
toString: () => string;
91103
};
104+
frozen: {
105+
toString: () => string;
106+
};
92107
};
93108
}
94109

test/balance-display.test.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { BitrielWalletSDK } from "../src/sdk";
2+
import { SUBSTRATE_NETWORKS, EVM_NETWORKS } from "../src/config/networks";
3+
import { DetailedBalance } from "../src/wallet/types";
4+
5+
async function testBalanceDisplay() {
6+
// Test mnemonic (replace with your test mnemonic)
7+
const mnemonic = "REPLACE_WITH_YOUR_TEST_MNEMONIC"; // DO NOT commit real mnemonics to version control
8+
9+
// Initialize the SDK with mnemonic
10+
const sdk = new BitrielWalletSDK(mnemonic);
11+
12+
try {
13+
// Test Substrate Chain (Selendra)
14+
console.log("\n=== Testing Balance Display on Selendra Network ===");
15+
const selendraNetwork = SUBSTRATE_NETWORKS.find(
16+
(n) => n.name === "Selendra"
17+
);
18+
if (selendraNetwork) {
19+
console.log("Connecting to Selendra network...");
20+
await sdk.connect(selendraNetwork.chainId.toString());
21+
22+
// Get detailed balance information
23+
console.log("\nGetting detailed balance information...");
24+
const detailedBalance = await sdk.getDetailedBalance();
25+
26+
// Display formatted balance information
27+
console.log("\nDetailed Balance Information:");
28+
console.log(
29+
"Total Balance:",
30+
detailedBalance.formatted.total,
31+
selendraNetwork.nativeCurrency.symbol
32+
);
33+
console.log(
34+
"Locked Balance:",
35+
detailedBalance.formatted.locked,
36+
selendraNetwork.nativeCurrency.symbol
37+
);
38+
console.log(
39+
"Transferable Balance:",
40+
detailedBalance.formatted.transferable,
41+
selendraNetwork.nativeCurrency.symbol
42+
);
43+
44+
// Verify balance calculations
45+
console.log("\nVerifying balance calculations...");
46+
const totalBigInt = BigInt(detailedBalance.total);
47+
const lockedBigInt = BigInt(detailedBalance.locked);
48+
const transferableBigInt = BigInt(detailedBalance.transferable);
49+
50+
console.log("Total (raw):", totalBigInt.toString());
51+
console.log("Locked (raw):", lockedBigInt.toString());
52+
console.log("Transferable (raw):", transferableBigInt.toString());
53+
54+
// Verify that total = locked + transferable
55+
const calculatedTotal = lockedBigInt + transferableBigInt;
56+
console.log("\nVerifying total = locked + transferable:");
57+
console.log("Calculated Total:", calculatedTotal.toString());
58+
console.log("Actual Total:", totalBigInt.toString());
59+
console.log("Match:", calculatedTotal === totalBigInt);
60+
61+
// Test balance formatting
62+
console.log("\nTesting balance formatting...");
63+
const formattedTotal = sdk.formatTokenBalance(
64+
detailedBalance.total,
65+
selendraNetwork.nativeCurrency.decimals,
66+
{ precision: 2 }
67+
);
68+
console.log("Formatted with 2 decimal places:", formattedTotal);
69+
70+
// Disconnect from Selendra
71+
await sdk.disconnect();
72+
}
73+
74+
// Test EVM Chain
75+
console.log("\n=== Testing Balance Display on EVM Network ===");
76+
const evmNetwork = EVM_NETWORKS.find(
77+
(n) => n.name === "Selendra Mainnet"
78+
);
79+
if (evmNetwork) {
80+
console.log("Connecting to EVM network...");
81+
await sdk.connect(evmNetwork.chainId.toString());
82+
83+
// Get detailed balance information
84+
console.log("\nGetting detailed balance information...");
85+
const detailedBalance = await sdk.getDetailedBalance();
86+
87+
// Display formatted balance information
88+
console.log("\nDetailed Balance Information:");
89+
console.log(
90+
"Total Balance:",
91+
detailedBalance.formatted.total,
92+
evmNetwork.nativeCurrency.symbol
93+
);
94+
console.log(
95+
"Locked Balance:",
96+
detailedBalance.formatted.locked,
97+
evmNetwork.nativeCurrency.symbol
98+
);
99+
console.log(
100+
"Transferable Balance:",
101+
detailedBalance.formatted.transferable,
102+
evmNetwork.nativeCurrency.symbol
103+
);
104+
105+
// Verify EVM balance properties
106+
console.log("\nVerifying EVM balance properties...");
107+
console.log(
108+
"Locked balance should be 0:",
109+
detailedBalance.locked === "0"
110+
);
111+
console.log(
112+
"Transferable should equal total:",
113+
detailedBalance.transferable === detailedBalance.total
114+
);
115+
116+
// Disconnect from EVM
117+
await sdk.disconnect();
118+
}
119+
} catch (error) {
120+
console.error("\nError during balance display test:", error);
121+
122+
// Detailed error logging
123+
if (error instanceof Error) {
124+
console.error("Error Name:", error.name);
125+
console.error("Error Message:", error.message);
126+
console.error("Error Stack:", error.stack);
127+
}
128+
}
129+
}
130+
131+
// Run the test
132+
testBalanceDisplay().catch(console.error);

test/wallet-sdk-excecute.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ async function main() {
3838

3939
// Test transaction
4040
const recipientAddress =
41-
"5DWespGr297iRHFDUijgnbYaxqhTNtesWRLXpJ5xFL8XdLGt";
41+
"5FFVzVi2xVs4XgHrRnb1ZW7h5iC1ojScAKvryPVvaXBXcrd9";
4242
const substrateTx = {
4343
method: "balances",
4444
params: [
4545
"transfer",
4646
recipientAddress,
47-
parseTransactionAmount("1", "substrate"),
48-
], // 1 SEL
47+
parseTransactionAmount("0.001", "substrate"),
48+
], // 0.001 SEL
4949
};
5050

5151
// Estimate fee before sending transaction

0 commit comments

Comments
 (0)