1- import fs from 'node:fs'
2- import { createRequire } from 'node:module'
3- import path from 'node:path'
4-
51import { Contract } from 'starknet'
62
7- import { createConnectionFactory } from '@layerzerolabs/devtools-starknet'
3+ import { createConnectionFactory , createRpcUrlFactory } from '@layerzerolabs/devtools-starknet'
84import { EndpointId , Stage , endpointIdToStage } from '@layerzerolabs/lz-definitions'
95
106import { SendResult } from '../common/types'
@@ -13,27 +9,21 @@ import { parseDecimalToUnits } from '../solana/utils'
139
1410import { assertStarknetEid , getStarknetAccountFromEnv } from './utils'
1511
16- const hexToBytes = ( value ?: string ) =>
17- value ? Uint8Array . from ( Buffer . from ( value . replace ( / ^ 0 x / , '' ) , 'hex' ) ) : new Uint8Array ( )
18-
19- const toCairoByteArray = ( hex ?: string ) => {
20- const clean = ( hex ?? '' ) . replace ( / ^ 0 x / , '' )
21- if ( ! clean ) {
22- return { data : [ ] , pending_word : '0x0' , pending_word_len : 0 }
23- }
24- const bytes = Buffer . from ( clean , 'hex' )
25- const chunkSize = 31
26- const data : string [ ] = [ ]
27- for ( let offset = 0 ; offset + chunkSize <= bytes . length ; offset += chunkSize ) {
28- data . push ( `0x${ bytes . subarray ( offset , offset + chunkSize ) . toString ( 'hex' ) } ` )
29- }
30- const remainder = bytes . length % chunkSize
31- const pendingBytes = remainder ? bytes . subarray ( bytes . length - remainder ) : Buffer . alloc ( 0 )
32- return {
33- data,
34- pending_word : pendingBytes . length ? `0x${ pendingBytes . toString ( 'hex' ) } ` : '0x0' ,
35- pending_word_len : pendingBytes . length ,
12+ /**
13+ * Convert hex string to a string for Cairo ByteArray.
14+ * In starknet.js v8, ByteArray parameters accept plain strings.
15+ *
16+ * NOTE: This uses latin1 encoding which can be corrupted by starknet.js's
17+ * UTF-8 re-encoding for bytes >= 128. For enforced options which typically
18+ * contain 0x80-0xFF bytes, use hexToByteArrayCalldata() with raw calldata.
19+ */
20+ const hexToString = ( hex ?: string ) : string => {
21+ if ( ! hex || hex === '0x' || hex === '' ) {
22+ return ''
3623 }
24+ const clean = hex . replace ( / ^ 0 x / , '' )
25+ const buffer = Buffer . from ( clean , 'hex' )
26+ return buffer . toString ( 'latin1' )
3727}
3828
3929export interface StarknetArgs {
@@ -61,12 +51,12 @@ export async function sendStarknet({
6151} : StarknetArgs ) : Promise < SendResult > {
6252 assertStarknetEid ( srcEid )
6353
64- const providerFactory = createConnectionFactory ( )
54+ // Use createRpcUrlFactory() to read from environment variables (RPC_URL_STARKNET)
55+ const providerFactory = createConnectionFactory ( createRpcUrlFactory ( ) )
6556 const provider = await providerFactory ( srcEid )
6657 const account = await getStarknetAccountFromEnv ( srcEid )
6758
68- const oftContract = await getOftMintBurnAdapterContract ( oftAddress , provider )
69- oftContract . connect ( account )
59+ const oftContract = await getOftMintBurnAdapterContract ( oftAddress , account )
7060
7161 const amountUnits = parseDecimalToUnits ( amount , tokenDecimals )
7262 const minAmountUnits = minAmount ? parseDecimalToUnits ( minAmount , tokenDecimals ) : amountUnits
@@ -76,9 +66,9 @@ export async function sendStarknet({
7666 to : { value : BigInt ( to ) } ,
7767 amount_ld : amountUnits ,
7868 min_amount_ld : minAmountUnits ,
79- extra_options : toCairoByteArray ( extraOptions ) ,
80- compose_msg : toCairoByteArray ( composeMsg ) ,
81- oft_cmd : toCairoByteArray ( ) ,
69+ extra_options : hexToString ( extraOptions ) ,
70+ compose_msg : hexToString ( composeMsg ) ,
71+ oft_cmd : hexToString ( ) ,
8272 }
8373
8474 const feeQuote = await oftContract . quote_send ( sendParam , false )
@@ -103,35 +93,17 @@ export async function sendStarknet({
10393}
10494
10595function getOftMintBurnAdapterAbi ( ) : unknown {
106- const require = createRequire ( import . meta. url )
107- const pkgRoot = path . dirname ( require . resolve ( '@layerzerolabs/oft-mint-burn-starknet/package.json' ) )
108- const candidates = [
109- 'dist/generated/abi/o-f-t-mint-burn-adapter.cjs' ,
110- 'dist/generated/abi/o-f-t-mint-burn-adapter.js' ,
111- 'contracts/oft_mint_burn/target/release/oft_mint_burn_OFTMintBurnAdapter.contract_class.json' ,
112- 'contracts/oft_mint_burn/target/dev/oft_mint_burn_OFTMintBurnAdapter.contract_class.json' ,
113- 'contracts/oft_mint_burn/target/release/oft_mint_burn_OFTMintBurnAdapter.compiled_contract_class.json' ,
114- 'contracts/oft_mint_burn/target/dev/oft_mint_burn_OFTMintBurnAdapter.compiled_contract_class.json' ,
115- ]
116-
117- for ( const relPath of candidates ) {
118- const fullPath = path . join ( pkgRoot , relPath )
119- if ( fs . existsSync ( fullPath ) ) {
120- if ( fullPath . endsWith ( '.js' ) || fullPath . endsWith ( '.cjs' ) ) {
121- return require ( fullPath )
122- }
123- const json = JSON . parse ( fs . readFileSync ( fullPath , 'utf8' ) )
124- return json . abi ?? json
125- }
96+ // Load the ABI from the package's main export
97+ // eslint-disable-next-line @typescript-eslint/no-var-requires
98+ const pkg = require ( '@layerzerolabs/oft-mint-burn-starknet' )
99+ const abi = pkg . abi ?. oFTMintBurnAdapter
100+ if ( ! abi ) {
101+ throw new Error ( 'Unable to locate OFTMintBurnAdapter ABI in @layerzerolabs/oft-mint-burn-starknet' )
126102 }
127-
128- throw new Error ( 'Unable to locate OFTMintBurnAdapter ABI in @layerzerolabs/oft-mint-burn-starknet' )
103+ return abi
129104}
130105
131- async function getOftMintBurnAdapterContract (
132- address : string ,
133- provider : ReturnType < typeof createConnectionFactory > extends ( ) => Promise < infer T > ? T : never
134- ) {
106+ async function getOftMintBurnAdapterContract ( address : string , providerOrAccount : any ) {
135107 const abi = getOftMintBurnAdapterAbi ( )
136- return new Contract ( { abi : abi as any , address, providerOrAccount : provider as any } )
108+ return new Contract ( { abi : abi as any , address, providerOrAccount } )
137109}
0 commit comments