@@ -8,6 +8,12 @@ const TOKEN_ADDRESSES = {
88 STRK : '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d'
99} ;
1010
11+ // Default decimals for common tokens
12+ const TOKEN_DECIMALS = {
13+ ETH : 18 ,
14+ STRK : 18
15+ } ;
16+
1117// Common interface for all transfer operations
1218interface TransferResult {
1319 txHash : string ;
@@ -23,19 +29,60 @@ interface TransferBaseParams {
2329 maxFee ?: string | bigint ;
2430}
2531
32+ /**
33+ * Converts a human-readable amount to token units
34+ * @param amount The amount in human-readable form (e.g., "0.00001")
35+ * @param decimals The number of decimals for the token
36+ * @returns The amount in token units as BigInt
37+ */
38+ function parseTokenAmount ( amount : string | bigint , decimals : number ) : bigint {
39+ // If amount is already a bigint, assume it's already in token units
40+ if ( typeof amount === 'bigint' ) {
41+ return amount ;
42+ }
43+
44+ // Handle decimal amounts
45+ const amountStr = amount . toString ( ) ;
46+
47+ // Check if the amount contains a decimal point
48+ if ( amountStr . includes ( '.' ) ) {
49+ const [ integerPart , fractionalPart = '' ] = amountStr . split ( '.' ) ;
50+
51+ // Ensure the fractional part isn't longer than allowed decimals
52+ if ( fractionalPart . length > decimals ) {
53+ throw new Error ( `Amount has too many decimal places. Maximum allowed: ${ decimals } ` ) ;
54+ }
55+
56+ // Pad the fractional part with zeros if needed
57+ const paddedFractionalPart = fractionalPart . padEnd ( decimals , '0' ) ;
58+
59+ // Combine the integer and fractional parts without the decimal point
60+ const combinedAmount = `${ integerPart } ${ paddedFractionalPart } ` ;
61+
62+ // Remove leading zeros (if any) and convert to BigInt
63+ return BigInt ( combinedAmount . replace ( / ^ 0 + / , '' ) || '0' ) ;
64+ }
65+
66+ // No decimal point, multiply by 10^decimals
67+ return BigInt ( amountStr ) * BigInt ( 10 ) ** BigInt ( decimals ) ;
68+ }
69+
2670/**
2771 * Prepare a transfer transaction
2872 * @param params Common transfer parameters
2973 * @param tokenAddress The token contract address
74+ * @param decimals The number of decimals for the token
3075 * @param network Network name
3176 * @returns Prepared account, transaction, and addresses
3277 */
3378async function prepareTransfer (
3479 params : TransferBaseParams ,
3580 tokenAddress : string ,
81+ decimals : number ,
3682 network : string
3783) {
38- const amount = typeof params . amount === 'string' ? BigInt ( params . amount ) : params . amount ;
84+ // Convert amount to token units, accounting for decimals
85+ const amount = parseTokenAmount ( params . amount , decimals ) ;
3986 const fromAddress = parseStarknetAddress ( params . from ) ;
4087
4188 // Resolve the 'to' parameter which could be either an address or a Starknet ID
@@ -115,6 +162,7 @@ export async function transferETH(
115162 const { account, tx } = await prepareTransfer (
116163 params ,
117164 TOKEN_ADDRESSES . ETH ,
165+ TOKEN_DECIMALS . ETH ,
118166 network
119167 ) ;
120168
@@ -139,6 +187,7 @@ export async function transferSTRK(
139187 const { account, tx } = await prepareTransfer (
140188 params ,
141189 TOKEN_ADDRESSES . STRK ,
190+ TOKEN_DECIMALS . STRK ,
142191 network
143192 ) ;
144193
@@ -156,15 +205,25 @@ export async function transferSTRK(
156205 * @returns Transaction details
157206 */
158207export async function transferERC20 (
159- params : TransferBaseParams & { tokenAddress : string } ,
208+ params : TransferBaseParams & { tokenAddress : string ; decimals ?: number } ,
160209 network = 'mainnet'
161210) : Promise < TransferResult > {
162211 try {
163212 const tokenAddress = parseStarknetAddress ( params . tokenAddress ) ;
164213
214+ // If decimals not provided, fetch them from the token contract
215+ let decimals = params . decimals ;
216+ if ( decimals === undefined ) {
217+ const provider = getProvider ( network ) ;
218+ const contract = getContract ( tokenAddress , provider , network ) ;
219+ const decimalsResponse = await contract . call ( 'decimals' , [ ] ) ;
220+ decimals = Number ( decimalsResponse . toString ( ) ) ;
221+ }
222+
165223 const { account, tx } = await prepareTransfer (
166224 params ,
167225 tokenAddress ,
226+ decimals ,
168227 network
169228 ) ;
170229
@@ -193,7 +252,6 @@ export async function executeContract(
193252 network = 'mainnet'
194253) : Promise < TransferResult > {
195254 try {
196- const provider = getProvider ( network ) ;
197255 const accountAddress = parseStarknetAddress ( params . accountAddress ) ;
198256
199257 // Resolve the contract address which could be either an address or a Starknet ID
0 commit comments