@glowlabs-org/utils 0.2.94 → 0.2.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -207,6 +207,8 @@ const mainnetAddresses = {
207
207
  USDG_UNISWAP: "0xe010ec500720bE9EF3F82129E7eD2Ee1FB7955F2",
208
208
  GLW_UNISWAP: "0xf4fbC617A5733EAAF9af08E1Ab816B103388d8B6",
209
209
  FORWARDER: "0x240CBe07a047ce484DCa2E3Ae15d4907Aba41BE2",
210
+ OFFCHAIN_FRACTIONS: "0x1Eca5C4391f10097C3232a0672e83c60A7dab7cD", // TODO: change to mainnet address
211
+ COUNTERFACTUAL_HOLDER_FACTORY: "0x2c3AB887746F6f4a8a4b9Db6aC800eb71945509A", // TODO: change to mainnet address
210
212
  FOUNDATION_WALLET: "0xc5174BBf649a92F9941e981af68AaA14Dd814F85",
211
213
  UNISWAP_V2_ROUTER: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
212
214
  UNISWAP_V2_FACTORY: "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f",
@@ -221,6 +223,8 @@ const sepoliaAddresses = {
221
223
  USDG_UNISWAP: "0x2a085A3aEA8982396533327c854753Ce521B666d",
222
224
  GLW_UNISWAP: "0x8e27016D0B866a56CE74A1a280c749dD679bb0Fa",
223
225
  FORWARDER: "0xDaC24F18171224eeaf6a9B38f5C5081aDbDff969",
226
+ OFFCHAIN_FRACTIONS: "0x1Eca5C4391f10097C3232a0672e83c60A7dab7cD",
227
+ COUNTERFACTUAL_HOLDER_FACTORY: "0x2c3AB887746F6f4a8a4b9Db6aC800eb71945509A",
224
228
  FOUNDATION_WALLET: "0x5e230FED487c86B90f6508104149F087d9B1B0A7",
225
229
  UNISWAP_V2_ROUTER: "0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3",
226
230
  UNISWAP_V2_FACTORY: "0xF62c03E08ada871A0bEb309762E260a7a6a880E6",
@@ -277,7 +281,7 @@ var ForwarderError;
277
281
  ForwarderError["MISSING_REQUIRED_PARAMS"] = "Missing required parameters";
278
282
  })(ForwarderError || (ForwarderError = {}));
279
283
  // Utility to extract the most useful revert reason from an ethers error object
280
- function parseEthersError(error) {
284
+ function parseEthersError$1(error) {
281
285
  if (!error)
282
286
  return "Unknown error";
283
287
  const possibleError = error;
@@ -304,7 +308,7 @@ function parseEthersError(error) {
304
308
  return ForwarderError.UNKNOWN_ERROR;
305
309
  }
306
310
  // Type-guard style helper to ensure a signer exists throughout the rest of the function.
307
- function assertSigner(maybeSigner) {
311
+ function assertSigner$1(maybeSigner) {
308
312
  if (!maybeSigner) {
309
313
  throw new Error(ForwarderError.SIGNER_NOT_AVAILABLE);
310
314
  }
@@ -319,7 +323,7 @@ function useForwarder(signer, CHAIN_ID) {
319
323
  };
320
324
  // Returns a contract instance for Forwarder
321
325
  function getForwarderContract() {
322
- assertSigner(signer);
326
+ assertSigner$1(signer);
323
327
  return new Contract(ADDRESSES.FORWARDER, FORWARDER_ABI, signer);
324
328
  }
325
329
  /**
@@ -381,7 +385,7 @@ function useForwarder(signer, CHAIN_ID) {
381
385
  * Get the appropriate token contract based on currency
382
386
  */
383
387
  function getTokenContract(currency = "USDC") {
384
- assertSigner(signer);
388
+ assertSigner$1(signer);
385
389
  let tokenAddress;
386
390
  switch (currency) {
387
391
  case "USDC":
@@ -404,7 +408,7 @@ function useForwarder(signer, CHAIN_ID) {
404
408
  * @param currency The currency to check allowance for
405
409
  */
406
410
  async function checkTokenAllowance(owner, currency = "USDC") {
407
- assertSigner(signer);
411
+ assertSigner$1(signer);
408
412
  try {
409
413
  const tokenContract = getTokenContract(currency);
410
414
  if (!tokenContract)
@@ -413,7 +417,7 @@ function useForwarder(signer, CHAIN_ID) {
413
417
  return allowance;
414
418
  }
415
419
  catch (error) {
416
- throw new Error(parseEthersError(error));
420
+ throw new Error(parseEthersError$1(error));
417
421
  }
418
422
  }
419
423
  /**
@@ -422,7 +426,7 @@ function useForwarder(signer, CHAIN_ID) {
422
426
  * @param currency The currency to check balance for
423
427
  */
424
428
  async function checkTokenBalance(owner, currency = "USDC") {
425
- assertSigner(signer);
429
+ assertSigner$1(signer);
426
430
  try {
427
431
  const tokenContract = getTokenContract(currency);
428
432
  if (!tokenContract)
@@ -431,7 +435,7 @@ function useForwarder(signer, CHAIN_ID) {
431
435
  return balance;
432
436
  }
433
437
  catch (error) {
434
- throw new Error(parseEthersError(error));
438
+ throw new Error(parseEthersError$1(error));
435
439
  }
436
440
  }
437
441
  /**
@@ -440,7 +444,7 @@ function useForwarder(signer, CHAIN_ID) {
440
444
  * @param currency The currency to approve
441
445
  */
442
446
  async function approveToken(amount, currency = "USDC") {
443
- assertSigner(signer);
447
+ assertSigner$1(signer);
444
448
  try {
445
449
  const tokenContract = getTokenContract(currency);
446
450
  if (!tokenContract)
@@ -452,7 +456,7 @@ function useForwarder(signer, CHAIN_ID) {
452
456
  return true;
453
457
  }
454
458
  catch (error) {
455
- throw new Error(parseEthersError(error));
459
+ throw new Error(parseEthersError$1(error));
456
460
  }
457
461
  finally {
458
462
  setIsProcessing(false);
@@ -463,7 +467,7 @@ function useForwarder(signer, CHAIN_ID) {
463
467
  * @param params Forward parameters including type, amount, and required fields
464
468
  */
465
469
  async function forwardTokens(params) {
466
- assertSigner(signer);
470
+ assertSigner$1(signer);
467
471
  try {
468
472
  const forwarderContract = getForwarderContract();
469
473
  if (!forwarderContract)
@@ -495,7 +499,7 @@ function useForwarder(signer, CHAIN_ID) {
495
499
  await approveTx.wait();
496
500
  }
497
501
  catch (approveError) {
498
- throw new Error(parseEthersError(approveError) || "Token approval failed");
502
+ throw new Error(parseEthersError$1(approveError) || "Token approval failed");
499
503
  }
500
504
  }
501
505
  // Get the token address based on currency
@@ -513,12 +517,14 @@ function useForwarder(signer, CHAIN_ID) {
513
517
  default:
514
518
  throw new Error(`Unsupported currency for forwarding: ${currency}`);
515
519
  }
520
+ // Determine sendToCounterfactualWallet based on currency
521
+ const sendToCounterfactualWallet = currency === "GLW" || currency === "USDG";
516
522
  // Run a static call first to surface any revert reason (ethers v6)
517
523
  try {
518
524
  if (!isAuditFees && currency === "USDC") {
519
525
  await forwarderContract
520
526
  .getFunction("swapUSDCAndForwardUSDG")
521
- .staticCall(amount, ADDRESSES.FOUNDATION_WALLET, true, message, {
527
+ .staticCall(amount, ADDRESSES.FOUNDATION_WALLET, sendToCounterfactualWallet, message, {
522
528
  from: owner,
523
529
  });
524
530
  }
@@ -527,27 +533,27 @@ function useForwarder(signer, CHAIN_ID) {
527
533
  .getFunction("forward")
528
534
  .staticCall(tokenAddress, isAuditFees
529
535
  ? ADDRESSES.AUDIT_FEE_WALLET
530
- : ADDRESSES.FOUNDATION_WALLET, amount, true, message, { from: owner });
536
+ : ADDRESSES.FOUNDATION_WALLET, amount, sendToCounterfactualWallet, message, { from: owner });
531
537
  }
532
538
  }
533
539
  catch (staticError) {
534
- throw new Error(parseEthersError(staticError));
540
+ throw new Error(parseEthersError$1(staticError));
535
541
  }
536
542
  // Execute the forward transaction
537
543
  let tx;
538
544
  if (!isAuditFees && currency === "USDC") {
539
- tx = await forwarderContract.getFunction("swapUSDCAndForwardUSDG")(amount, ADDRESSES.FOUNDATION_WALLET, true, message);
545
+ tx = await forwarderContract.getFunction("swapUSDCAndForwardUSDG")(amount, ADDRESSES.FOUNDATION_WALLET, sendToCounterfactualWallet, message);
540
546
  }
541
547
  else {
542
548
  tx = await forwarderContract.getFunction("forward")(tokenAddress, isAuditFees
543
549
  ? ADDRESSES.AUDIT_FEE_WALLET
544
- : ADDRESSES.FOUNDATION_WALLET, amount, true, message);
550
+ : ADDRESSES.FOUNDATION_WALLET, amount, sendToCounterfactualWallet, message);
545
551
  }
546
552
  await tx.wait();
547
553
  return tx.hash;
548
554
  }
549
555
  catch (txError) {
550
- throw new Error(parseEthersError(txError));
556
+ throw new Error(parseEthersError$1(txError));
551
557
  }
552
558
  finally {
553
559
  setIsProcessing(false);
@@ -557,7 +563,7 @@ function useForwarder(signer, CHAIN_ID) {
557
563
  * Forward tokens for protocol fee payment and GCTL minting with staking
558
564
  */
559
565
  async function payProtocolFeeAndMintGCTLAndStake(amount, userAddress, applicationId, regionId, currency = "USDC") {
560
- assertSigner(signer);
566
+ assertSigner$1(signer);
561
567
  // GCTL minting only supports USDC and USDG
562
568
  if (currency === "GLW") {
563
569
  throw new Error("GCTL minting is not supported with GLW payment. Use USDC or USDG.");
@@ -575,7 +581,7 @@ function useForwarder(signer, CHAIN_ID) {
575
581
  * Forward tokens for protocol fee payment and GCTL minting with staking
576
582
  */
577
583
  async function sponsorProtocolFeeAndMintGCTLAndStake(amount, userAddress, applicationId, currency = "USDC") {
578
- assertSigner(signer);
584
+ assertSigner$1(signer);
579
585
  if (currency === "GLW") {
580
586
  throw new Error("GCTL minting is not supported with GLW payment. Use USDC or USDG.");
581
587
  }
@@ -591,7 +597,7 @@ function useForwarder(signer, CHAIN_ID) {
591
597
  * Forward tokens for protocol fee payment only
592
598
  */
593
599
  async function payProtocolFee(amount, userAddress, applicationId, currency = "USDC") {
594
- assertSigner(signer);
600
+ assertSigner$1(signer);
595
601
  return forwardTokens({
596
602
  amount,
597
603
  userAddress,
@@ -604,7 +610,7 @@ function useForwarder(signer, CHAIN_ID) {
604
610
  * Forward tokens for protocol fee payment only
605
611
  */
606
612
  async function sponsorProtocolFee(amount, userAddress, applicationId, currency = "USDC") {
607
- assertSigner(signer);
613
+ assertSigner$1(signer);
608
614
  return forwardTokens({
609
615
  amount,
610
616
  userAddress,
@@ -617,7 +623,7 @@ function useForwarder(signer, CHAIN_ID) {
617
623
  * Forward USDC to mint GCTL and stake to a region
618
624
  */
619
625
  async function mintGCTLAndStake(amount, userAddress, regionId, currency = "USDC") {
620
- assertSigner(signer);
626
+ assertSigner$1(signer);
621
627
  // GCTL minting only supports USDC and USDG
622
628
  if (currency === "GLW") {
623
629
  throw new Error("GCTL minting is not supported with GLW payment. Use USDC or USDG.");
@@ -634,7 +640,7 @@ function useForwarder(signer, CHAIN_ID) {
634
640
  * Forward USDC to mint GCTL (existing functionality, keeping for compatibility)
635
641
  */
636
642
  async function mintGCTL(amount, userAddress, currency = "USDC") {
637
- assertSigner(signer);
643
+ assertSigner$1(signer);
638
644
  // GCTL minting only supports USDC and USDG
639
645
  if (currency === "GLW") {
640
646
  throw new Error("GCTL minting is not supported with GLW payment. Use USDC or USDG.");
@@ -650,7 +656,7 @@ function useForwarder(signer, CHAIN_ID) {
650
656
  * Forward tokens to pay audit fees (USDC only, calls forward())
651
657
  */
652
658
  async function payAuditFees(amount, userAddress, applicationId) {
653
- assertSigner(signer);
659
+ assertSigner$1(signer);
654
660
  return forwardTokens({
655
661
  amount,
656
662
  userAddress,
@@ -663,7 +669,7 @@ function useForwarder(signer, CHAIN_ID) {
663
669
  * Forward tokens to buy a solar farm
664
670
  */
665
671
  async function buySolarFarm(amount, userAddress, farmId, currency = "USDC") {
666
- assertSigner(signer);
672
+ assertSigner$1(signer);
667
673
  return forwardTokens({
668
674
  amount,
669
675
  userAddress,
@@ -676,7 +682,7 @@ function useForwarder(signer, CHAIN_ID) {
676
682
  * Forward tokens to commit to a Kickstarter (USDC or USDG only)
677
683
  */
678
684
  async function commitKickstarter(amount, userAddress, kickstarterId, currency = "USDC") {
679
- assertSigner(signer);
685
+ assertSigner$1(signer);
680
686
  if (currency === "GLW") {
681
687
  throw new Error("CommitKickstarter supports only USDC or USDG");
682
688
  }
@@ -694,7 +700,7 @@ function useForwarder(signer, CHAIN_ID) {
694
700
  * @param ethPriceInUSD Current ETH price in USD (for cost estimation)
695
701
  */
696
702
  async function estimateGasForForward(params, ethPriceInUSD) {
697
- assertSigner(signer);
703
+ assertSigner$1(signer);
698
704
  try {
699
705
  const forwarderContract = getForwarderContract();
700
706
  if (!forwarderContract)
@@ -706,6 +712,8 @@ function useForwarder(signer, CHAIN_ID) {
706
712
  }
707
713
  // Construct the appropriate message for this forward type
708
714
  const message = constructForwardMessage(params);
715
+ // Determine sendToCounterfactualWallet based on currency
716
+ const sendToCounterfactualWallet = currency === "GLW" || currency === "USDG";
709
717
  // Get token address
710
718
  let tokenAddress;
711
719
  switch (currency) {
@@ -729,12 +737,12 @@ function useForwarder(signer, CHAIN_ID) {
729
737
  const estimatedGas = !isAuditFees && currency === "USDC"
730
738
  ? await forwarderContract
731
739
  .getFunction("swapUSDCAndForwardUSDG")
732
- .estimateGas(amount, ADDRESSES.FOUNDATION_WALLET, true, message)
740
+ .estimateGas(amount, ADDRESSES.FOUNDATION_WALLET, sendToCounterfactualWallet, message)
733
741
  : await forwarderContract
734
742
  .getFunction("forward")
735
743
  .estimateGas(tokenAddress, isAuditFees
736
744
  ? ADDRESSES.AUDIT_FEE_WALLET
737
- : ADDRESSES.FOUNDATION_WALLET, amount, true, message);
745
+ : ADDRESSES.FOUNDATION_WALLET, amount, sendToCounterfactualWallet, message);
738
746
  const estimatedCost = estimatedGas * gasPrice;
739
747
  if (ethPriceInUSD) {
740
748
  const estimatedCostInEth = formatEther(estimatedCost);
@@ -746,7 +754,7 @@ function useForwarder(signer, CHAIN_ID) {
746
754
  }
747
755
  }
748
756
  catch (error) {
749
- throw new Error(parseEthersError(error));
757
+ throw new Error(parseEthersError$1(error));
750
758
  }
751
759
  }
752
760
  /**
@@ -755,7 +763,7 @@ function useForwarder(signer, CHAIN_ID) {
755
763
  * @param recipient Address to mint USDC to
756
764
  */
757
765
  async function mintTestUSDC(amount, recipient) {
758
- assertSigner(signer);
766
+ assertSigner$1(signer);
759
767
  if (CHAIN_ID !== 11155111) {
760
768
  throw new Error("Minting test USDC is only supported on Sepolia");
761
769
  }
@@ -771,7 +779,7 @@ function useForwarder(signer, CHAIN_ID) {
771
779
  }
772
780
  catch (error) {
773
781
  // If mint function doesn't exist or fails, provide helpful error
774
- const errorMessage = parseEthersError(error);
782
+ const errorMessage = parseEthersError$1(error);
775
783
  if (errorMessage.includes("mint")) {
776
784
  throw new Error("This USDC contract doesn't support minting");
777
785
  }
@@ -811,6 +819,861 @@ function useForwarder(signer, CHAIN_ID) {
811
819
  };
812
820
  }
813
821
 
822
+ const OFFCHAIN_FRACTIONS_ABI = [
823
+ {
824
+ inputs: [
825
+ {
826
+ internalType: "contract CounterfactualHolderFactory",
827
+ name: "_counterfactualHolderFactory",
828
+ type: "address",
829
+ },
830
+ ],
831
+ stateMutability: "nonpayable",
832
+ type: "constructor",
833
+ },
834
+ {
835
+ inputs: [{ internalType: "address", name: "target", type: "address" }],
836
+ name: "AddressEmptyCode",
837
+ type: "error",
838
+ },
839
+ {
840
+ inputs: [{ internalType: "address", name: "account", type: "address" }],
841
+ name: "AddressInsufficientBalance",
842
+ type: "error",
843
+ },
844
+ { inputs: [], name: "AlreadyClaimed", type: "error" },
845
+ { inputs: [], name: "AlreadyClosed", type: "error" },
846
+ { inputs: [], name: "AlreadyExists", type: "error" },
847
+ { inputs: [], name: "AlreadySent", type: "error" },
848
+ {
849
+ inputs: [],
850
+ name: "CannotClaimPayoutWhenRoundNotFullyFilled",
851
+ type: "error",
852
+ },
853
+ { inputs: [], name: "CannotClaimRefundWhenNotExpired", type: "error" },
854
+ { inputs: [], name: "CannotClaimRefundWhenRoundFullyFilled", type: "error" },
855
+ { inputs: [], name: "CannotCloseAFullRound", type: "error" },
856
+ { inputs: [], name: "CannotHaveZeroTotalSteps", type: "error" },
857
+ { inputs: [], name: "Expired", type: "error" },
858
+ { inputs: [], name: "FailedInnerCall", type: "error" },
859
+ { inputs: [], name: "InsufficientSharesAvailable", type: "error" },
860
+ { inputs: [], name: "InvalidToAddress", type: "error" },
861
+ { inputs: [], name: "InvalidToken", type: "error" },
862
+ { inputs: [], name: "MinSharesCannotBeGreaterThanTotalSteps", type: "error" },
863
+ { inputs: [], name: "NoStepsPurchased", type: "error" },
864
+ { inputs: [], name: "NotAllOrNothing", type: "error" },
865
+ { inputs: [], name: "NotFractionsOwner", type: "error" },
866
+ { inputs: [], name: "RecipientCannotBeSelf", type: "error" },
867
+ { inputs: [], name: "ReentrancyGuardReentrantCall", type: "error" },
868
+ {
869
+ inputs: [{ internalType: "address", name: "token", type: "address" }],
870
+ name: "SafeERC20FailedOperation",
871
+ type: "error",
872
+ },
873
+ { inputs: [], name: "StepMustBeGreaterThanZero", type: "error" },
874
+ { inputs: [], name: "TaxTokenNotSupported", type: "error" },
875
+ { inputs: [], name: "TotalRaisedOverflow", type: "error" },
876
+ { inputs: [], name: "ZeroSteps", type: "error" },
877
+ {
878
+ anonymous: false,
879
+ inputs: [
880
+ { indexed: true, internalType: "bytes32", name: "id", type: "bytes32" },
881
+ {
882
+ indexed: true,
883
+ internalType: "address",
884
+ name: "token",
885
+ type: "address",
886
+ },
887
+ {
888
+ indexed: true,
889
+ internalType: "address",
890
+ name: "owner",
891
+ type: "address",
892
+ },
893
+ ],
894
+ name: "FractionClosed",
895
+ type: "event",
896
+ },
897
+ {
898
+ anonymous: false,
899
+ inputs: [
900
+ { indexed: true, internalType: "bytes32", name: "id", type: "bytes32" },
901
+ {
902
+ indexed: true,
903
+ internalType: "address",
904
+ name: "token",
905
+ type: "address",
906
+ },
907
+ {
908
+ indexed: true,
909
+ internalType: "address",
910
+ name: "owner",
911
+ type: "address",
912
+ },
913
+ {
914
+ indexed: false,
915
+ internalType: "uint256",
916
+ name: "step",
917
+ type: "uint256",
918
+ },
919
+ {
920
+ indexed: false,
921
+ internalType: "uint256",
922
+ name: "totalSteps",
923
+ type: "uint256",
924
+ },
925
+ {
926
+ indexed: false,
927
+ internalType: "uint48",
928
+ name: "expiration",
929
+ type: "uint48",
930
+ },
931
+ { indexed: false, internalType: "address", name: "to", type: "address" },
932
+ {
933
+ indexed: false,
934
+ internalType: "bool",
935
+ name: "useCounterfactualAddress",
936
+ type: "bool",
937
+ },
938
+ {
939
+ indexed: false,
940
+ internalType: "uint256",
941
+ name: "minSharesToRaise",
942
+ type: "uint256",
943
+ },
944
+ ],
945
+ name: "FractionCreated",
946
+ type: "event",
947
+ },
948
+ {
949
+ anonymous: false,
950
+ inputs: [
951
+ { indexed: true, internalType: "bytes32", name: "id", type: "bytes32" },
952
+ {
953
+ indexed: true,
954
+ internalType: "address",
955
+ name: "creator",
956
+ type: "address",
957
+ },
958
+ { indexed: true, internalType: "address", name: "user", type: "address" },
959
+ {
960
+ indexed: false,
961
+ internalType: "uint256",
962
+ name: "amount",
963
+ type: "uint256",
964
+ },
965
+ ],
966
+ name: "FractionRefunded",
967
+ type: "event",
968
+ },
969
+ {
970
+ anonymous: false,
971
+ inputs: [
972
+ { indexed: true, internalType: "bytes32", name: "id", type: "bytes32" },
973
+ {
974
+ indexed: true,
975
+ internalType: "address",
976
+ name: "creator",
977
+ type: "address",
978
+ },
979
+ {
980
+ indexed: true,
981
+ internalType: "address",
982
+ name: "buyer",
983
+ type: "address",
984
+ },
985
+ {
986
+ indexed: false,
987
+ internalType: "uint256",
988
+ name: "step",
989
+ type: "uint256",
990
+ },
991
+ {
992
+ indexed: false,
993
+ internalType: "uint256",
994
+ name: "amount",
995
+ type: "uint256",
996
+ },
997
+ ],
998
+ name: "FractionSold",
999
+ type: "event",
1000
+ },
1001
+ {
1002
+ anonymous: false,
1003
+ inputs: [
1004
+ { indexed: true, internalType: "bytes32", name: "id", type: "bytes32" },
1005
+ {
1006
+ indexed: true,
1007
+ internalType: "address",
1008
+ name: "creator",
1009
+ type: "address",
1010
+ },
1011
+ {
1012
+ indexed: false,
1013
+ internalType: "uint256",
1014
+ name: "minShares",
1015
+ type: "uint256",
1016
+ },
1017
+ {
1018
+ indexed: false,
1019
+ internalType: "uint256",
1020
+ name: "newTotalSharesSold",
1021
+ type: "uint256",
1022
+ },
1023
+ ],
1024
+ name: "MinSharesReached",
1025
+ type: "event",
1026
+ },
1027
+ {
1028
+ anonymous: false,
1029
+ inputs: [
1030
+ { indexed: true, internalType: "bytes32", name: "id", type: "bytes32" },
1031
+ {
1032
+ indexed: true,
1033
+ internalType: "address",
1034
+ name: "creator",
1035
+ type: "address",
1036
+ },
1037
+ ],
1038
+ name: "RoundFilled",
1039
+ type: "event",
1040
+ },
1041
+ {
1042
+ inputs: [
1043
+ { internalType: "address", name: "creator", type: "address" },
1044
+ { internalType: "bytes32", name: "id", type: "bytes32" },
1045
+ { internalType: "uint256", name: "stepsToBuy", type: "uint256" },
1046
+ { internalType: "uint256", name: "minStepsToBuy", type: "uint256" },
1047
+ ],
1048
+ name: "buyFractions",
1049
+ outputs: [],
1050
+ stateMutability: "nonpayable",
1051
+ type: "function",
1052
+ },
1053
+ {
1054
+ inputs: [
1055
+ { internalType: "address", name: "creator", type: "address" },
1056
+ { internalType: "bytes32", name: "id", type: "bytes32" },
1057
+ ],
1058
+ name: "claimRefund",
1059
+ outputs: [],
1060
+ stateMutability: "nonpayable",
1061
+ type: "function",
1062
+ },
1063
+ {
1064
+ inputs: [{ internalType: "bytes32", name: "id", type: "bytes32" }],
1065
+ name: "closeFraction",
1066
+ outputs: [],
1067
+ stateMutability: "nonpayable",
1068
+ type: "function",
1069
+ },
1070
+ {
1071
+ inputs: [
1072
+ { internalType: "bytes32", name: "id", type: "bytes32" },
1073
+ { internalType: "address", name: "token", type: "address" },
1074
+ { internalType: "uint256", name: "step", type: "uint256" },
1075
+ { internalType: "uint256", name: "totalSteps", type: "uint256" },
1076
+ { internalType: "uint48", name: "expiration", type: "uint48" },
1077
+ { internalType: "address", name: "to", type: "address" },
1078
+ { internalType: "bool", name: "useCounterfactualAddress", type: "bool" },
1079
+ { internalType: "uint256", name: "minSharesToRaise", type: "uint256" },
1080
+ ],
1081
+ name: "createFraction",
1082
+ outputs: [],
1083
+ stateMutability: "nonpayable",
1084
+ type: "function",
1085
+ },
1086
+ {
1087
+ inputs: [
1088
+ { internalType: "address", name: "creator", type: "address" },
1089
+ { internalType: "bytes32", name: "id", type: "bytes32" },
1090
+ ],
1091
+ name: "getFraction",
1092
+ outputs: [
1093
+ {
1094
+ components: [
1095
+ { internalType: "address", name: "token", type: "address" },
1096
+ { internalType: "uint48", name: "expiration", type: "uint48" },
1097
+ { internalType: "bool", name: "manuallyClosed", type: "bool" },
1098
+ {
1099
+ internalType: "uint256",
1100
+ name: "minSharesToRaise",
1101
+ type: "uint256",
1102
+ },
1103
+ {
1104
+ internalType: "bool",
1105
+ name: "useCounterfactualAddress",
1106
+ type: "bool",
1107
+ },
1108
+ {
1109
+ internalType: "bool",
1110
+ name: "claimedFromMinSharesToRaise",
1111
+ type: "bool",
1112
+ },
1113
+ { internalType: "address", name: "owner", type: "address" },
1114
+ { internalType: "uint256", name: "step", type: "uint256" },
1115
+ { internalType: "address", name: "to", type: "address" },
1116
+ { internalType: "uint256", name: "soldSteps", type: "uint256" },
1117
+ { internalType: "uint256", name: "totalSteps", type: "uint256" },
1118
+ ],
1119
+ internalType: "struct OffchainFractions.FractionData",
1120
+ name: "",
1121
+ type: "tuple",
1122
+ },
1123
+ ],
1124
+ stateMutability: "view",
1125
+ type: "function",
1126
+ },
1127
+ {
1128
+ inputs: [],
1129
+ name: "i_CFHFactory",
1130
+ outputs: [
1131
+ {
1132
+ internalType: "contract CounterfactualHolderFactory",
1133
+ name: "",
1134
+ type: "address",
1135
+ },
1136
+ ],
1137
+ stateMutability: "view",
1138
+ type: "function",
1139
+ },
1140
+ {
1141
+ inputs: [
1142
+ { internalType: "address", name: "user", type: "address" },
1143
+ { internalType: "address", name: "creator", type: "address" },
1144
+ { internalType: "bytes32", name: "id", type: "bytes32" },
1145
+ ],
1146
+ name: "stepsPurchased",
1147
+ outputs: [
1148
+ { internalType: "uint256", name: "stepsPurchased", type: "uint256" },
1149
+ ],
1150
+ stateMutability: "view",
1151
+ type: "function",
1152
+ },
1153
+ ];
1154
+
1155
+ var OffchainFractionsError;
1156
+ (function (OffchainFractionsError) {
1157
+ OffchainFractionsError["CONTRACT_NOT_AVAILABLE"] = "Contract not available";
1158
+ OffchainFractionsError["SIGNER_NOT_AVAILABLE"] = "Signer not available";
1159
+ OffchainFractionsError["UNKNOWN_ERROR"] = "Unknown error";
1160
+ OffchainFractionsError["INVALID_PARAMETERS"] = "Invalid parameters";
1161
+ OffchainFractionsError["FRACTION_NOT_FOUND"] = "Fraction not found";
1162
+ OffchainFractionsError["INSUFFICIENT_BALANCE"] = "Insufficient balance";
1163
+ OffchainFractionsError["INSUFFICIENT_ALLOWANCE"] = "Insufficient allowance";
1164
+ })(OffchainFractionsError || (OffchainFractionsError = {}));
1165
+ // Utility to extract the most useful revert reason from an ethers error object
1166
+ function parseEthersError(error) {
1167
+ if (!error)
1168
+ return "Unknown error";
1169
+ const possibleError = error;
1170
+ // If the error originates from a callStatic it will often be found at `error?.error?.body`
1171
+ if (possibleError?.error?.body) {
1172
+ try {
1173
+ const body = JSON.parse(possibleError.error.body);
1174
+ // Hardhat style errors
1175
+ if (body?.error?.message)
1176
+ return body.error.message;
1177
+ }
1178
+ catch { }
1179
+ }
1180
+ // Found on MetaMask/Alchemy shape errors
1181
+ if (possibleError?.data?.message)
1182
+ return possibleError.data.message;
1183
+ if (possibleError?.error?.message)
1184
+ return possibleError.error.message;
1185
+ // Standard ethers v5 message
1186
+ if (possibleError?.reason)
1187
+ return possibleError.reason;
1188
+ if (possibleError?.message)
1189
+ return possibleError.message;
1190
+ return OffchainFractionsError.UNKNOWN_ERROR;
1191
+ }
1192
+ // Type-guard style helper to ensure a signer exists throughout the rest of the function.
1193
+ function assertSigner(maybeSigner) {
1194
+ if (!maybeSigner) {
1195
+ throw new Error(OffchainFractionsError.SIGNER_NOT_AVAILABLE);
1196
+ }
1197
+ }
1198
+ function useOffchainFractions(signer, CHAIN_ID) {
1199
+ // Use dynamic addresses based on chain configuration
1200
+ const ADDRESSES = getAddresses(CHAIN_ID);
1201
+ // Framework-agnostic processing flag
1202
+ let isProcessing = false;
1203
+ const setIsProcessing = (value) => {
1204
+ isProcessing = value;
1205
+ };
1206
+ // Returns a contract instance for OffchainFractions
1207
+ function getOffchainFractionsContract() {
1208
+ assertSigner(signer);
1209
+ return new Contract(ADDRESSES.OFFCHAIN_FRACTIONS, OFFCHAIN_FRACTIONS_ABI, signer);
1210
+ }
1211
+ /**
1212
+ * Get the appropriate token contract
1213
+ */
1214
+ function getTokenContract(tokenAddress) {
1215
+ assertSigner(signer);
1216
+ return new Contract(tokenAddress, ERC20_ABI, signer);
1217
+ }
1218
+ /**
1219
+ * Check current token allowance for the offchain fractions contract
1220
+ * @param owner The wallet address to check allowance for
1221
+ * @param tokenAddress The token contract address
1222
+ */
1223
+ async function checkTokenAllowance(owner, tokenAddress) {
1224
+ assertSigner(signer);
1225
+ try {
1226
+ const tokenContract = getTokenContract(tokenAddress);
1227
+ if (!tokenContract)
1228
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1229
+ const allowance = await tokenContract.allowance(owner, ADDRESSES.OFFCHAIN_FRACTIONS);
1230
+ return allowance;
1231
+ }
1232
+ catch (error) {
1233
+ throw new Error(parseEthersError(error));
1234
+ }
1235
+ }
1236
+ /**
1237
+ * Check user's token balance
1238
+ * @param owner The wallet address to check balance for
1239
+ * @param tokenAddress The token contract address
1240
+ */
1241
+ async function checkTokenBalance(owner, tokenAddress) {
1242
+ assertSigner(signer);
1243
+ try {
1244
+ const tokenContract = getTokenContract(tokenAddress);
1245
+ if (!tokenContract)
1246
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1247
+ const balance = await tokenContract.balanceOf(owner);
1248
+ return balance;
1249
+ }
1250
+ catch (error) {
1251
+ throw new Error(parseEthersError(error));
1252
+ }
1253
+ }
1254
+ /**
1255
+ * Approve tokens for the offchain fractions contract
1256
+ * @param tokenAddress The token contract address
1257
+ * @param amount Amount to approve (BigNumber)
1258
+ */
1259
+ async function approveToken(tokenAddress, amount) {
1260
+ assertSigner(signer);
1261
+ try {
1262
+ const tokenContract = getTokenContract(tokenAddress);
1263
+ if (!tokenContract)
1264
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1265
+ setIsProcessing(true);
1266
+ const approveTx = await tokenContract.approve(ADDRESSES.OFFCHAIN_FRACTIONS, amount);
1267
+ await approveTx.wait();
1268
+ return true;
1269
+ }
1270
+ catch (error) {
1271
+ throw new Error(parseEthersError(error));
1272
+ }
1273
+ finally {
1274
+ setIsProcessing(false);
1275
+ }
1276
+ }
1277
+ /**
1278
+ * Create a new fractional token sale
1279
+ * @param params Parameters for creating the fraction
1280
+ */
1281
+ async function createFraction(params) {
1282
+ assertSigner(signer);
1283
+ try {
1284
+ const contract = getOffchainFractionsContract();
1285
+ if (!contract)
1286
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1287
+ setIsProcessing(true);
1288
+ const { id, token, step, totalSteps, expiration, to, useCounterfactualAddress, minSharesToRaise, } = params;
1289
+ // Validate parameters
1290
+ if (!id || !token || !to) {
1291
+ throw new Error(OffchainFractionsError.INVALID_PARAMETERS);
1292
+ }
1293
+ if (step === 0n || totalSteps === 0n) {
1294
+ throw new Error("Step and totalSteps must be greater than zero");
1295
+ }
1296
+ if (minSharesToRaise > totalSteps) {
1297
+ throw new Error("minSharesToRaise cannot be greater than totalSteps");
1298
+ }
1299
+ // Run a static call first to surface any revert reason
1300
+ try {
1301
+ await contract
1302
+ .getFunction("createFraction")
1303
+ .staticCall(id, token, step, totalSteps, expiration, to, useCounterfactualAddress, minSharesToRaise);
1304
+ }
1305
+ catch (staticError) {
1306
+ throw new Error(parseEthersError(staticError));
1307
+ }
1308
+ // Execute the transaction
1309
+ const tx = await contract.getFunction("createFraction")(id, token, step, totalSteps, expiration, to, useCounterfactualAddress, minSharesToRaise);
1310
+ await tx.wait();
1311
+ return tx.hash;
1312
+ }
1313
+ catch (error) {
1314
+ throw new Error(parseEthersError(error));
1315
+ }
1316
+ finally {
1317
+ setIsProcessing(false);
1318
+ }
1319
+ }
1320
+ /**
1321
+ * Buy fractions in an existing sale
1322
+ * @param params Parameters for buying fractions
1323
+ */
1324
+ async function buyFractions(params) {
1325
+ assertSigner(signer);
1326
+ try {
1327
+ const contract = getOffchainFractionsContract();
1328
+ if (!contract)
1329
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1330
+ setIsProcessing(true);
1331
+ const { creator, id, stepsToBuy, minStepsToBuy } = params;
1332
+ // Validate parameters
1333
+ if (!creator || !id) {
1334
+ throw new Error(OffchainFractionsError.INVALID_PARAMETERS);
1335
+ }
1336
+ if (stepsToBuy === 0n) {
1337
+ throw new Error("stepsToBuy must be greater than zero");
1338
+ }
1339
+ // Get fraction data to calculate required amount
1340
+ const fractionData = await getFraction(creator, id);
1341
+ const requiredAmount = stepsToBuy * fractionData.step;
1342
+ const owner = await signer.getAddress();
1343
+ // Check token balance
1344
+ const balance = await checkTokenBalance(owner, fractionData.token);
1345
+ if (balance < requiredAmount) {
1346
+ throw new Error(OffchainFractionsError.INSUFFICIENT_BALANCE);
1347
+ }
1348
+ // Check and approve tokens if necessary
1349
+ const allowance = await checkTokenAllowance(owner, fractionData.token);
1350
+ if (allowance < requiredAmount) {
1351
+ const tokenContract = getTokenContract(fractionData.token);
1352
+ const approveTx = await tokenContract.approve(ADDRESSES.OFFCHAIN_FRACTIONS, requiredAmount);
1353
+ await approveTx.wait();
1354
+ }
1355
+ // Run a static call first to surface any revert reason
1356
+ try {
1357
+ await contract
1358
+ .getFunction("buyFractions")
1359
+ .staticCall(creator, id, stepsToBuy, minStepsToBuy, {
1360
+ from: owner,
1361
+ });
1362
+ }
1363
+ catch (staticError) {
1364
+ throw new Error(parseEthersError(staticError));
1365
+ }
1366
+ // Execute the transaction
1367
+ const tx = await contract.getFunction("buyFractions")(creator, id, stepsToBuy, minStepsToBuy);
1368
+ await tx.wait();
1369
+ return tx.hash;
1370
+ }
1371
+ catch (error) {
1372
+ throw new Error(parseEthersError(error));
1373
+ }
1374
+ finally {
1375
+ setIsProcessing(false);
1376
+ }
1377
+ }
1378
+ /**
1379
+ * Claim refund from an unfilled sale
1380
+ * @param creator The address that created the fraction sale
1381
+ * @param id The unique identifier of the fraction sale
1382
+ */
1383
+ async function claimRefund(creator, id) {
1384
+ assertSigner(signer);
1385
+ try {
1386
+ const contract = getOffchainFractionsContract();
1387
+ if (!contract)
1388
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1389
+ setIsProcessing(true);
1390
+ // Validate parameters
1391
+ if (!creator || !id) {
1392
+ throw new Error(OffchainFractionsError.INVALID_PARAMETERS);
1393
+ }
1394
+ const owner = await signer.getAddress();
1395
+ // Check if user has steps purchased
1396
+ const userSteps = await getStepsPurchased(owner, creator, id);
1397
+ if (userSteps === 0n) {
1398
+ throw new Error("No steps purchased for this fraction");
1399
+ }
1400
+ // Run a static call first to surface any revert reason
1401
+ try {
1402
+ await contract.getFunction("claimRefund").staticCall(creator, id, {
1403
+ from: owner,
1404
+ });
1405
+ }
1406
+ catch (staticError) {
1407
+ throw new Error(parseEthersError(staticError));
1408
+ }
1409
+ // Execute the transaction
1410
+ const tx = await contract.getFunction("claimRefund")(creator, id);
1411
+ await tx.wait();
1412
+ return tx.hash;
1413
+ }
1414
+ catch (error) {
1415
+ throw new Error(parseEthersError(error));
1416
+ }
1417
+ finally {
1418
+ setIsProcessing(false);
1419
+ }
1420
+ }
1421
+ /**
1422
+ * Close a fraction sale manually (only by owner)
1423
+ * @param id The unique identifier of the fraction sale to close
1424
+ */
1425
+ async function closeFraction(id) {
1426
+ assertSigner(signer);
1427
+ try {
1428
+ const contract = getOffchainFractionsContract();
1429
+ if (!contract)
1430
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1431
+ setIsProcessing(true);
1432
+ // Validate parameters
1433
+ if (!id) {
1434
+ throw new Error(OffchainFractionsError.INVALID_PARAMETERS);
1435
+ }
1436
+ const owner = await signer.getAddress();
1437
+ // Run a static call first to surface any revert reason
1438
+ try {
1439
+ await contract.getFunction("closeFraction").staticCall(id, {
1440
+ from: owner,
1441
+ });
1442
+ }
1443
+ catch (staticError) {
1444
+ throw new Error(parseEthersError(staticError));
1445
+ }
1446
+ // Execute the transaction
1447
+ const tx = await contract.getFunction("closeFraction")(id);
1448
+ await tx.wait();
1449
+ return tx.hash;
1450
+ }
1451
+ catch (error) {
1452
+ throw new Error(parseEthersError(error));
1453
+ }
1454
+ finally {
1455
+ setIsProcessing(false);
1456
+ }
1457
+ }
1458
+ /**
1459
+ * Get fraction data for a specific creator and ID
1460
+ * @param creator The address that created the fraction sale
1461
+ * @param id The unique identifier of the fraction sale
1462
+ */
1463
+ async function getFraction(creator, id) {
1464
+ assertSigner(signer);
1465
+ try {
1466
+ const contract = getOffchainFractionsContract();
1467
+ if (!contract)
1468
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1469
+ const result = await contract.getFraction(creator, id);
1470
+ return {
1471
+ token: result.token,
1472
+ expiration: Number(result.expiration),
1473
+ manuallyClosed: result.manuallyClosed,
1474
+ minSharesToRaise: result.minSharesToRaise,
1475
+ useCounterfactualAddress: result.useCounterfactualAddress,
1476
+ claimedFromMinSharesToRaise: result.claimedFromMinSharesToRaise,
1477
+ owner: result.owner,
1478
+ step: result.step,
1479
+ to: result.to,
1480
+ soldSteps: result.soldSteps,
1481
+ totalSteps: result.totalSteps,
1482
+ };
1483
+ }
1484
+ catch (error) {
1485
+ throw new Error(parseEthersError(error));
1486
+ }
1487
+ }
1488
+ /**
1489
+ * Get the number of steps purchased by a user for a specific fraction
1490
+ * @param user The user address
1491
+ * @param creator The address that created the fraction sale
1492
+ * @param id The unique identifier of the fraction sale
1493
+ */
1494
+ async function getStepsPurchased(user, creator, id) {
1495
+ assertSigner(signer);
1496
+ try {
1497
+ const contract = getOffchainFractionsContract();
1498
+ if (!contract)
1499
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1500
+ const result = await contract.stepsPurchased(user, creator, id);
1501
+ return result;
1502
+ }
1503
+ catch (error) {
1504
+ throw new Error(parseEthersError(error));
1505
+ }
1506
+ }
1507
+ /**
1508
+ * Check if a fraction sale is expired
1509
+ * @param creator The address that created the fraction sale
1510
+ * @param id The unique identifier of the fraction sale
1511
+ */
1512
+ async function isFractionExpired(creator, id) {
1513
+ try {
1514
+ const fraction = await getFraction(creator, id);
1515
+ return Date.now() / 1000 > fraction.expiration;
1516
+ }
1517
+ catch (error) {
1518
+ throw new Error(parseEthersError(error));
1519
+ }
1520
+ }
1521
+ /**
1522
+ * Check if a fraction sale has reached its minimum shares threshold
1523
+ * @param creator The address that created the fraction sale
1524
+ * @param id The unique identifier of the fraction sale
1525
+ */
1526
+ async function hasReachedMinimumShares(creator, id) {
1527
+ try {
1528
+ const fraction = await getFraction(creator, id);
1529
+ return fraction.soldSteps >= fraction.minSharesToRaise;
1530
+ }
1531
+ catch (error) {
1532
+ throw new Error(parseEthersError(error));
1533
+ }
1534
+ }
1535
+ /**
1536
+ * Check if a fraction sale is completely filled
1537
+ * @param creator The address that created the fraction sale
1538
+ * @param id The unique identifier of the fraction sale
1539
+ */
1540
+ async function isFractionCompletelyFilled(creator, id) {
1541
+ try {
1542
+ const fraction = await getFraction(creator, id);
1543
+ return fraction.soldSteps >= fraction.totalSteps;
1544
+ }
1545
+ catch (error) {
1546
+ throw new Error(parseEthersError(error));
1547
+ }
1548
+ }
1549
+ /**
1550
+ * Calculate the total amount raised for a fraction
1551
+ * @param creator The address that created the fraction sale
1552
+ * @param id The unique identifier of the fraction sale
1553
+ */
1554
+ async function getTotalAmountRaised(creator, id) {
1555
+ try {
1556
+ const fraction = await getFraction(creator, id);
1557
+ return fraction.soldSteps * fraction.step;
1558
+ }
1559
+ catch (error) {
1560
+ throw new Error(parseEthersError(error));
1561
+ }
1562
+ }
1563
+ /**
1564
+ * Calculate the remaining steps available for purchase
1565
+ * @param creator The address that created the fraction sale
1566
+ * @param id The unique identifier of the fraction sale
1567
+ */
1568
+ async function getRemainingSteps(creator, id) {
1569
+ try {
1570
+ const fraction = await getFraction(creator, id);
1571
+ return fraction.totalSteps - fraction.soldSteps;
1572
+ }
1573
+ catch (error) {
1574
+ throw new Error(parseEthersError(error));
1575
+ }
1576
+ }
1577
+ /**
1578
+ * Estimate gas for creating a fraction
1579
+ * @param params Parameters for creating the fraction
1580
+ * @param ethPriceInUSD Current ETH price in USD (for cost estimation)
1581
+ */
1582
+ async function estimateGasForCreateFraction(params, ethPriceInUSD) {
1583
+ assertSigner(signer);
1584
+ try {
1585
+ const contract = getOffchainFractionsContract();
1586
+ if (!contract)
1587
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1588
+ const { id, token, step, totalSteps, expiration, to, useCounterfactualAddress, minSharesToRaise, } = params;
1589
+ const feeData = await signer.provider?.getFeeData();
1590
+ const gasPrice = feeData?.gasPrice ?? feeData?.maxFeePerGas ?? 0n;
1591
+ if (gasPrice === 0n) {
1592
+ throw new Error("Could not fetch gas price to estimate cost.");
1593
+ }
1594
+ const estimatedGas = await contract
1595
+ .getFunction("createFraction")
1596
+ .estimateGas(id, token, step, totalSteps, expiration, to, useCounterfactualAddress, minSharesToRaise);
1597
+ const estimatedCost = estimatedGas * gasPrice;
1598
+ if (ethPriceInUSD) {
1599
+ const estimatedCostInEth = formatEther(estimatedCost);
1600
+ const estimatedCostInUSD = (parseFloat(estimatedCostInEth) * ethPriceInUSD).toFixed(2);
1601
+ return estimatedCostInUSD;
1602
+ }
1603
+ else {
1604
+ throw new Error("Could not fetch the ETH price to calculate cost in USD.");
1605
+ }
1606
+ }
1607
+ catch (error) {
1608
+ throw new Error(parseEthersError(error));
1609
+ }
1610
+ }
1611
+ /**
1612
+ * Estimate gas for buying fractions
1613
+ * @param params Parameters for buying fractions
1614
+ * @param ethPriceInUSD Current ETH price in USD (for cost estimation)
1615
+ */
1616
+ async function estimateGasForBuyFractions(params, ethPriceInUSD) {
1617
+ assertSigner(signer);
1618
+ try {
1619
+ const contract = getOffchainFractionsContract();
1620
+ if (!contract)
1621
+ throw new Error(OffchainFractionsError.CONTRACT_NOT_AVAILABLE);
1622
+ const { creator, id, stepsToBuy, minStepsToBuy } = params;
1623
+ const feeData = await signer.provider?.getFeeData();
1624
+ const gasPrice = feeData?.gasPrice ?? feeData?.maxFeePerGas ?? 0n;
1625
+ if (gasPrice === 0n) {
1626
+ throw new Error("Could not fetch gas price to estimate cost.");
1627
+ }
1628
+ const estimatedGas = await contract
1629
+ .getFunction("buyFractions")
1630
+ .estimateGas(creator, id, stepsToBuy, minStepsToBuy);
1631
+ const estimatedCost = estimatedGas * gasPrice;
1632
+ if (ethPriceInUSD) {
1633
+ const estimatedCostInEth = formatEther(estimatedCost);
1634
+ const estimatedCostInUSD = (parseFloat(estimatedCostInEth) * ethPriceInUSD).toFixed(2);
1635
+ return estimatedCostInUSD;
1636
+ }
1637
+ else {
1638
+ throw new Error("Could not fetch the ETH price to calculate cost in USD.");
1639
+ }
1640
+ }
1641
+ catch (error) {
1642
+ throw new Error(parseEthersError(error));
1643
+ }
1644
+ }
1645
+ return {
1646
+ // Core contract functions
1647
+ createFraction,
1648
+ buyFractions,
1649
+ claimRefund,
1650
+ closeFraction,
1651
+ // View functions
1652
+ getFraction,
1653
+ getStepsPurchased,
1654
+ // Token operations
1655
+ approveToken,
1656
+ checkTokenAllowance,
1657
+ checkTokenBalance,
1658
+ // Utility functions
1659
+ isFractionExpired,
1660
+ hasReachedMinimumShares,
1661
+ isFractionCompletelyFilled,
1662
+ getTotalAmountRaised,
1663
+ getRemainingSteps,
1664
+ // Gas estimation
1665
+ estimateGasForCreateFraction,
1666
+ estimateGasForBuyFractions,
1667
+ // State
1668
+ get isProcessing() {
1669
+ return isProcessing;
1670
+ },
1671
+ addresses: ADDRESSES,
1672
+ // Signer availability
1673
+ isSignerAvailable: !!signer,
1674
+ };
1675
+ }
1676
+
814
1677
  // --------------------------------------------------------------------------
815
1678
  /**
816
1679
  * Extract a useful error message from an unknown error value.
@@ -2158,5 +3021,5 @@ function FarmsRouter(baseUrl) {
2158
3021
  };
2159
3022
  }
2160
3023
 
2161
- export { ControlRouter as C, DECIMALS_BY_TOKEN as D, FarmsRouter as F, GLOW_WEIGHT_DECIMAL_PRECISION as G, HUB_URL as H, KickstarterRouter as K, MAX_WEIGHT as M, OFF_CHAIN_PAYMENT_CURRENCIES as O, PAYMENT_CURRENCIES as P, RegionRouter as R, TRANSFER_TYPES as T, USDG_WEIGHT_DECIMAL_PRECISION as U, WalletsRouter as W, ForwarderError as a, allRegions as b, usStates as c, countries as d, FORWARDER_ABI as e, GCA_URLS as f, getAddresses as g, regionMetadata as r, useForwarder as u };
2162
- //# sourceMappingURL=farms-router-sm5H9Ax6.js.map
3024
+ export { ControlRouter as C, DECIMALS_BY_TOKEN as D, FarmsRouter as F, GLOW_WEIGHT_DECIMAL_PRECISION as G, HUB_URL as H, KickstarterRouter as K, MAX_WEIGHT as M, OffchainFractionsError as O, PAYMENT_CURRENCIES as P, RegionRouter as R, TRANSFER_TYPES as T, USDG_WEIGHT_DECIMAL_PRECISION as U, WalletsRouter as W, useOffchainFractions as a, ForwarderError as b, OFF_CHAIN_PAYMENT_CURRENCIES as c, allRegions as d, usStates as e, countries as f, FORWARDER_ABI as g, getAddresses as h, GCA_URLS as i, regionMetadata as r, useForwarder as u };
3025
+ //# sourceMappingURL=farms-router-BCnakF0d.js.map