@@ -312,6 +312,117 @@ export class SorobanService {
312312 } ;
313313 }
314314
315+ /**
316+ * Build unsigned file_claim transaction.
317+ * Signature: file_claim(holder, policy_id, amount, details, image_urls)
318+ */
319+ async buildFileClaimTransaction ( args : {
320+ holder : string ;
321+ policyId : number ;
322+ amount : bigint ;
323+ details : string ;
324+ imageUrls : string [ ] ;
325+ } ) : Promise < BuildTransactionResult > {
326+ const server = this . makeServer ( ) ;
327+ const account = await this . loadAccount ( server , args . holder ) ;
328+ const ledgerInfo = await server . getLatestLedger ( ) ;
329+
330+ const scArgs = [
331+ new Address ( args . holder ) . toScVal ( ) ,
332+ nativeToScVal ( args . policyId , { type : 'u32' } ) ,
333+ nativeToScVal ( args . amount , { type : 'i128' } ) ,
334+ nativeToScVal ( args . details , { type : 'string' } ) ,
335+ xdr . ScVal . scvVec (
336+ args . imageUrls . map ( ( url ) => nativeToScVal ( url , { type : 'string' } ) ) ,
337+ ) ,
338+ ] ;
339+
340+ const contract = new Contract ( this . contractId ) ;
341+ const tx = new TransactionBuilder ( account , {
342+ fee : BASE_FEE ,
343+ networkPassphrase : this . networkPassphrase ,
344+ } )
345+ . addOperation ( contract . call ( 'file_claim' , ...scArgs ) )
346+ . setTimeout ( 30 )
347+ . build ( ) ;
348+
349+ const simulation = await server . simulateTransaction ( tx ) ;
350+
351+ if ( Api . isSimulationError ( simulation ) ) {
352+ const err = simulation as SorobanRpc . Api . SimulateTransactionErrorResponse ;
353+ this . mapSimulationError ( err . error ) ;
354+ }
355+
356+ const successSim =
357+ simulation as SorobanRpc . Api . SimulateTransactionSuccessResponse ;
358+ const assembled = assembleTransaction ( tx , successSim ) ;
359+ const unsignedXdr = assembled . build ( ) . toEnvelope ( ) . toXDR ( 'base64' ) ;
360+
361+ const baseFee = BigInt ( BASE_FEE ) ;
362+ const resourceFee = BigInt ( successSim . minResourceFee ?? '0' ) ;
363+ const totalFee = baseFee + resourceFee ;
364+
365+ const authRequirements : AuthRequirement [ ] = [ ] ;
366+ for ( const authEntry of successSim . result ?. auth ?? [ ] ) {
367+ const credentials = authEntry . credentials ( ) ;
368+ if (
369+ credentials . switch ( ) . value ===
370+ xdr . SorobanCredentialsType . sorobanCredentialsAddress ( ) . value
371+ ) {
372+ const addrObj = credentials . address ( ) . address ( ) ;
373+ const stellarAddr = Address . fromScAddress ( addrObj ) ;
374+ const isContract =
375+ addrObj . switch ( ) . value ===
376+ xdr . ScAddressType . scAddressTypeContract ( ) . value ;
377+ authRequirements . push ( { address : stellarAddr . toString ( ) , isContract } ) ;
378+ }
379+ }
380+
381+ if ( ! authRequirements . some ( ( r ) => r . address === args . holder ) ) {
382+ authRequirements . unshift ( { address : args . holder , isContract : false } ) ;
383+ }
384+
385+ return {
386+ unsignedXdr,
387+ minResourceFee : successSim . minResourceFee ?? '0' ,
388+ baseFee : BASE_FEE . toString ( ) ,
389+ totalEstimatedFee : totalFee . toString ( ) ,
390+ totalEstimatedFeeXlm : SorobanService . stroopsToXlm ( totalFee ) ,
391+ authRequirements,
392+ memoConvention :
393+ 'NiffyInsure does not use memos for protocol correlation. ' +
394+ 'Claim details are embedded in the contract call.' ,
395+ currentLedger : ledgerInfo . sequence ,
396+ } ;
397+ }
398+
399+ /**
400+ * Submit a signed transaction to the Soroban RPC.
401+ * Expects base64-encoded XDR (envelope).
402+ */
403+ async submitTransaction ( transactionXdr : string ) : Promise < SorobanRpc . Api . SendTransactionResponse > {
404+ const server = this . makeServer ( ) ;
405+ const tx = TransactionBuilder . fromEnvelope ( transactionXdr , this . networkPassphrase ) ;
406+
407+ try {
408+ const response = await server . sendTransaction ( tx ) ;
409+ if ( response . status === 'ERROR' ) {
410+ throw new BadRequestException ( {
411+ code : 'TRANSACTION_REJECTED' ,
412+ message : 'The transaction was rejected by the network.' ,
413+ details : response . errorResultXdr ,
414+ } ) ;
415+ }
416+ return response ;
417+ } catch ( err ) {
418+ this . logger . error ( 'Transaction submission error' , err ) ;
419+ throw new ServiceUnavailableException ( {
420+ code : 'SUBMISSION_FAILED' ,
421+ message : 'Failed to submit transaction to the network.' ,
422+ } ) ;
423+ }
424+ }
425+
315426 /**
316427 * Fetch events for the configured contract ID within a ledger range.
317428 */
0 commit comments