@compass-labs/widgets 0.1.36 → 0.1.37

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.
package/dist/index.js CHANGED
@@ -7771,13 +7771,18 @@ function WithdrawModal({ isOpen, onClose, initialToken, allowedTokens }) {
7771
7771
  }
7772
7772
  function getPhase2(step) {
7773
7773
  if (step === "idle" || step === "failed") return 0;
7774
- if (step === "preparing-permit" || step === "signing-permit") return 1;
7774
+ if (step === "approving" || step === "signing-approval") return 1;
7775
7775
  return 2;
7776
7776
  }
7777
+ var EVM_CHAIN_IDS3 = {
7778
+ ethereum: 1,
7779
+ base: 8453,
7780
+ arbitrum: 42161
7781
+ };
7777
7782
  function TopUpModal({ isOpen, onClose }) {
7778
7783
  const { address, signTypedData, switchChain, walletChainId } = useEmbeddableWallet();
7779
- const { chainId, chain } = useChain();
7780
- const { creditAccountAddress, isDeployed } = useCreditAccount();
7784
+ const { chainId } = useChain();
7785
+ const { isDeployed } = useCreditAccount();
7781
7786
  const queryClient = reactQuery.useQueryClient();
7782
7787
  const prices = useTokenPrices();
7783
7788
  const token = "USDC";
@@ -7795,13 +7800,14 @@ function TopUpModal({ isOpen, onClose }) {
7795
7800
  react.useEffect(() => {
7796
7801
  return () => clearPolling();
7797
7802
  }, [clearPolling]);
7803
+ const CHAIN_ID = chainId;
7798
7804
  const { data: walletBalance } = reactQuery.useQuery({
7799
- queryKey: ["walletTokenBalance", chainId, address, token],
7805
+ queryKey: ["walletTokenBalance", CHAIN_ID, address, token],
7800
7806
  queryFn: async () => {
7801
7807
  if (!address) return "0";
7802
7808
  try {
7803
7809
  const res = await fetch(
7804
- `/api/compass/token/balance?address=${address}&chain=${chainId}&token=${token}`
7810
+ `/api/compass/token/balance?address=${address}&chain=${CHAIN_ID}&token=${token}`
7805
7811
  );
7806
7812
  if (!res.ok) return "0";
7807
7813
  const data = await res.json();
@@ -7827,142 +7833,175 @@ function TopUpModal({ isOpen, onClose }) {
7827
7833
  setTxState({ status: "idle" });
7828
7834
  };
7829
7835
  const isValid = Number(amount) > 0 && !!address && isDeployed;
7830
- const isBusy = step === "preparing-permit" || step === "signing-permit" || step === "preparing-bundle" || step === "signing-bundle" || step === "broadcasting";
7836
+ const isBusy = step === "approving" || step === "signing-approval" || step === "preparing-transfer" || step === "signing-transfer" || step === "executing";
7837
+ const ensureCorrectChain = react.useCallback(async () => {
7838
+ const targetChainId = EVM_CHAIN_IDS3[CHAIN_ID];
7839
+ if (!targetChainId) return;
7840
+ if (walletChainId !== void 0 && walletChainId !== targetChainId) {
7841
+ if (!switchChain) {
7842
+ throw new Error(`Please switch your wallet to ${CHAIN_ID} (chain ${targetChainId})`);
7843
+ }
7844
+ await switchChain(targetChainId);
7845
+ }
7846
+ }, [walletChainId, switchChain, CHAIN_ID]);
7831
7847
  const handleTransfer = async () => {
7832
- if (!isValid) return;
7848
+ if (!isValid || !signTypedData) return;
7849
+ setTxState({ status: "idle" });
7833
7850
  try {
7834
- if (switchChain && walletChainId !== chain.viemChain.id) {
7835
- await switchChain(chain.viemChain.id);
7836
- }
7851
+ await ensureCorrectChain();
7837
7852
  if (action === "deposit") {
7838
- setStep("preparing-permit");
7853
+ setStep("approving");
7839
7854
  setTxState({ status: "preparing" });
7840
- const transferResponse = await fetch("/api/compass/credit/transfer", {
7855
+ const approveResponse = await fetch("/api/compass/transfer/approve", {
7841
7856
  method: "POST",
7842
7857
  headers: { "Content-Type": "application/json" },
7843
7858
  body: JSON.stringify({
7844
7859
  owner: address,
7845
- chain: chainId,
7846
- token,
7847
- amount: Number(amount)
7860
+ chain: CHAIN_ID,
7861
+ token
7848
7862
  })
7849
7863
  });
7850
- if (!transferResponse.ok) {
7851
- const errorData = await transferResponse.json();
7852
- throw new Error(errorData.error || "Failed to prepare permit");
7864
+ if (!approveResponse.ok) {
7865
+ const errData = await approveResponse.json();
7866
+ throw new Error(errData.error || "Failed to check approval");
7853
7867
  }
7854
- const transferData = await transferResponse.json();
7855
- const permit2Eip712 = transferData.eip712;
7856
- setStep("signing-permit");
7857
- setTxState({ status: "signing" });
7858
- const permit2Signature = await signTypedData({
7859
- domain: permit2Eip712.domain,
7860
- types: {
7861
- PermitTransferFrom: transferData.normalizedTypes.PermitTransferFrom,
7862
- TokenPermissions: transferData.normalizedTypes.TokenPermissions
7863
- },
7864
- primaryType: "PermitTransferFrom",
7865
- message: permit2Eip712.message
7866
- });
7867
- setStep("preparing-bundle");
7868
+ const approvalData = await approveResponse.json();
7869
+ if (!approvalData.approved) {
7870
+ if (approvalData.requiresTransaction && approvalData.transaction) {
7871
+ setTxState({ status: "broadcasting" });
7872
+ const executeApprovalResponse = await fetch("/api/compass/approval/execute", {
7873
+ method: "POST",
7874
+ headers: { "Content-Type": "application/json" },
7875
+ body: JSON.stringify({
7876
+ owner: address,
7877
+ chain: CHAIN_ID,
7878
+ transaction: approvalData.transaction
7879
+ })
7880
+ });
7881
+ if (!executeApprovalResponse.ok) {
7882
+ const errData = await executeApprovalResponse.json();
7883
+ throw new Error(errData.error || "Approval transaction failed");
7884
+ }
7885
+ } else if (approvalData.eip712) {
7886
+ setStep("signing-approval");
7887
+ setTxState({ status: "signing" });
7888
+ const approvalSignature = await signTypedData({
7889
+ domain: approvalData.domain,
7890
+ types: approvalData.normalizedTypes,
7891
+ primaryType: "Permit",
7892
+ message: approvalData.message
7893
+ });
7894
+ setTxState({ status: "broadcasting" });
7895
+ const executeApprovalResponse = await fetch("/api/compass/transfer/execute", {
7896
+ method: "POST",
7897
+ headers: { "Content-Type": "application/json" },
7898
+ body: JSON.stringify({
7899
+ owner: address,
7900
+ chain: CHAIN_ID,
7901
+ eip712: approvalData.eip712,
7902
+ signature: approvalSignature
7903
+ })
7904
+ });
7905
+ if (!executeApprovalResponse.ok) {
7906
+ const errData = await executeApprovalResponse.json();
7907
+ throw new Error(errData.error || "Approval failed");
7908
+ }
7909
+ } else {
7910
+ throw new Error("Unable to approve token for transfers");
7911
+ }
7912
+ }
7913
+ setStep("preparing-transfer");
7868
7914
  setTxState({ status: "preparing" });
7869
- const bundlePrepareResponse = await fetch("/api/compass/credit/bundle/prepare", {
7915
+ const prepareResponse = await fetch("/api/compass/transfer/prepare", {
7870
7916
  method: "POST",
7871
7917
  headers: { "Content-Type": "application/json" },
7872
7918
  body: JSON.stringify({
7873
7919
  owner: address,
7874
- chain: chainId,
7875
- actions: [
7876
- {
7877
- actionType: "V2_TRANSFER_FROM_EOA",
7878
- token,
7879
- amount: Number(amount),
7880
- permit2Signature,
7881
- permit2Nonce: permit2Eip712.message.nonce,
7882
- permit2Deadline: permit2Eip712.message.deadline
7883
- }
7884
- ]
7920
+ chain: CHAIN_ID,
7921
+ token,
7922
+ amount,
7923
+ action: "DEPOSIT",
7924
+ product: "credit"
7885
7925
  })
7886
7926
  });
7887
- if (!bundlePrepareResponse.ok) {
7888
- const errorData = await bundlePrepareResponse.json();
7889
- throw new Error(errorData.error || "Failed to prepare bundle");
7927
+ if (!prepareResponse.ok) {
7928
+ const errData = await prepareResponse.json();
7929
+ throw new Error(errData.error || "Failed to prepare transfer");
7890
7930
  }
7891
- const { eip712, normalizedTypes, domain, message } = await bundlePrepareResponse.json();
7892
- setStep("signing-bundle");
7931
+ const prepareData = await prepareResponse.json();
7932
+ setStep("signing-transfer");
7893
7933
  setTxState({ status: "signing" });
7894
- const safeTxSignature = await signTypedData({
7895
- domain,
7896
- types: normalizedTypes,
7897
- primaryType: "SafeTx",
7898
- message
7934
+ await ensureCorrectChain();
7935
+ const signature = await signTypedData({
7936
+ domain: prepareData.domain,
7937
+ types: prepareData.normalizedTypes,
7938
+ primaryType: prepareData.primaryType,
7939
+ message: prepareData.message
7899
7940
  });
7900
- setStep("broadcasting");
7941
+ setStep("executing");
7901
7942
  setTxState({ status: "broadcasting" });
7902
- const executeResponse = await fetch("/api/compass/credit/bundle/execute", {
7943
+ const executeResponse = await fetch("/api/compass/transfer/execute", {
7903
7944
  method: "POST",
7904
7945
  headers: { "Content-Type": "application/json" },
7905
7946
  body: JSON.stringify({
7906
7947
  owner: address,
7907
- eip712,
7908
- signature: safeTxSignature,
7909
- chain: chainId,
7910
- creditAccountAddress
7948
+ chain: CHAIN_ID,
7949
+ eip712: prepareData.eip712,
7950
+ signature,
7951
+ product: "credit"
7911
7952
  })
7912
7953
  });
7913
7954
  if (!executeResponse.ok) {
7914
- const errorData = await executeResponse.json();
7915
- throw new Error(errorData.error || "Failed to execute");
7955
+ const errData = await executeResponse.json();
7956
+ throw new Error(errData.error || "Transfer failed");
7916
7957
  }
7917
7958
  const { txHash } = await executeResponse.json();
7918
7959
  handleSuccess(txHash);
7919
7960
  } else {
7920
- setStep("preparing-bundle");
7961
+ setStep("preparing-transfer");
7921
7962
  setTxState({ status: "preparing" });
7922
- const bundlePrepareResponse = await fetch("/api/compass/credit/bundle/prepare", {
7963
+ const prepareResponse = await fetch("/api/compass/transfer/prepare", {
7923
7964
  method: "POST",
7924
7965
  headers: { "Content-Type": "application/json" },
7925
7966
  body: JSON.stringify({
7926
7967
  owner: address,
7927
- chain: chainId,
7928
- actions: [
7929
- {
7930
- actionType: "V2_TRANSFER_TO_EOA",
7931
- token,
7932
- amount: Number(amount)
7933
- }
7934
- ]
7968
+ chain: CHAIN_ID,
7969
+ token,
7970
+ amount,
7971
+ action: "WITHDRAW",
7972
+ product: "credit"
7935
7973
  })
7936
7974
  });
7937
- if (!bundlePrepareResponse.ok) {
7938
- const errorData = await bundlePrepareResponse.json();
7939
- throw new Error(errorData.error || "Failed to prepare withdrawal");
7975
+ if (!prepareResponse.ok) {
7976
+ const errData = await prepareResponse.json();
7977
+ throw new Error(errData.error || "Failed to prepare withdrawal");
7940
7978
  }
7941
- const { eip712, normalizedTypes, domain, message } = await bundlePrepareResponse.json();
7942
- setStep("signing-bundle");
7979
+ const prepareData = await prepareResponse.json();
7980
+ setStep("signing-transfer");
7943
7981
  setTxState({ status: "signing" });
7944
- const safeTxSignature = await signTypedData({
7945
- domain,
7946
- types: normalizedTypes,
7947
- primaryType: "SafeTx",
7948
- message
7982
+ await ensureCorrectChain();
7983
+ const signature = await signTypedData({
7984
+ domain: prepareData.domain,
7985
+ types: prepareData.normalizedTypes,
7986
+ primaryType: prepareData.primaryType,
7987
+ message: prepareData.message
7949
7988
  });
7950
- setStep("broadcasting");
7989
+ setStep("executing");
7951
7990
  setTxState({ status: "broadcasting" });
7952
- const executeResponse = await fetch("/api/compass/credit/bundle/execute", {
7991
+ const executeResponse = await fetch("/api/compass/transfer/execute", {
7953
7992
  method: "POST",
7954
7993
  headers: { "Content-Type": "application/json" },
7955
7994
  body: JSON.stringify({
7956
7995
  owner: address,
7957
- eip712,
7958
- signature: safeTxSignature,
7959
- chain: chainId,
7960
- creditAccountAddress
7996
+ chain: CHAIN_ID,
7997
+ eip712: prepareData.eip712,
7998
+ signature,
7999
+ product: "credit"
7961
8000
  })
7962
8001
  });
7963
8002
  if (!executeResponse.ok) {
7964
- const errorData = await executeResponse.json();
7965
- throw new Error(errorData.error || "Failed to execute withdrawal");
8003
+ const errData = await executeResponse.json();
8004
+ throw new Error(errData.error || "Withdrawal failed");
7966
8005
  }
7967
8006
  const { txHash } = await executeResponse.json();
7968
8007
  handleSuccess(txHash);
@@ -7985,8 +8024,9 @@ function TopUpModal({ isOpen, onClose }) {
7985
8024
  polls++;
7986
8025
  queryClient.invalidateQueries({ queryKey: ["creditBalances"] });
7987
8026
  queryClient.invalidateQueries({ queryKey: ["creditPositions"] });
8027
+ queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
7988
8028
  try {
7989
- const res = await fetch(`/api/compass/tx/receipt?hash=${txHash}&chain=${chainId}`);
8029
+ const res = await fetch(`/api/compass/tx/receipt?hash=${txHash}&chain=${CHAIN_ID}`);
7990
8030
  const data = await res.json();
7991
8031
  if (data.status === "success") {
7992
8032
  clearPolling();
@@ -8001,23 +8041,23 @@ function TopUpModal({ isOpen, onClose }) {
8001
8041
  }
8002
8042
  if (polls >= 24) {
8003
8043
  clearPolling();
8004
- setTxState({ status: "confirmed", txHash });
8044
+ setTxState({ status: "failed", error: "Unable to confirm transaction. Please check your wallet for status." });
8005
8045
  }
8006
8046
  }, 5e3);
8007
8047
  };
8008
8048
  const phase = getPhase2(step);
8009
8049
  const buttonLabel = () => {
8010
8050
  switch (step) {
8011
- case "preparing-permit":
8012
- return "Preparing approval...";
8013
- case "signing-permit":
8051
+ case "approving":
8052
+ return "Checking approval...";
8053
+ case "signing-approval":
8014
8054
  return "Sign Approval (1/2)...";
8015
- case "preparing-bundle":
8055
+ case "preparing-transfer":
8016
8056
  return action === "deposit" ? "Preparing transfer..." : "Preparing withdrawal...";
8017
- case "signing-bundle":
8057
+ case "signing-transfer":
8018
8058
  return action === "deposit" ? "Sign Transfer (2/2)..." : "Sign Withdrawal...";
8019
- case "broadcasting":
8020
- return "Broadcasting...";
8059
+ case "executing":
8060
+ return "Executing...";
8021
8061
  default:
8022
8062
  return null;
8023
8063
  }
@@ -8100,7 +8140,10 @@ function TopUpModal({ isOpen, onClose }) {
8100
8140
  {
8101
8141
  type: "number",
8102
8142
  value: amount,
8103
- onChange: (e) => setAmount(e.target.value),
8143
+ onChange: (e) => {
8144
+ setAmount(e.target.value);
8145
+ setTxState({ status: "idle" });
8146
+ },
8104
8147
  disabled: isBusy,
8105
8148
  placeholder: "0.00",
8106
8149
  className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
@@ -8142,7 +8185,7 @@ function TopUpModal({ isOpen, onClose }) {
8142
8185
  }
8143
8186
  )
8144
8187
  ] }),
8145
- !isBusy && step !== "confirmed" && step !== "failed" && /* @__PURE__ */ jsxRuntime.jsx(
8188
+ !isBusy && step !== "confirmed" && step !== "failed" && txState.status === "idle" && /* @__PURE__ */ jsxRuntime.jsx(
8146
8189
  "p",
8147
8190
  {
8148
8191
  className: "text-xs",
@@ -10771,7 +10814,7 @@ function AllocationEditor({
10771
10814
  ) })
10772
10815
  ] });
10773
10816
  }
10774
- var EVM_CHAIN_IDS3 = {
10817
+ var EVM_CHAIN_IDS4 = {
10775
10818
  ethereum: 1,
10776
10819
  base: 8453,
10777
10820
  arbitrum: 42161
@@ -10950,7 +10993,7 @@ function RebalancingWidget({
10950
10993
  setTargets((prev) => prev.map((t, i) => i === index ? { ...t, targetPercent: rounded } : t));
10951
10994
  }, []);
10952
10995
  const ensureCorrectChain = react.useCallback(async () => {
10953
- const targetChainId = EVM_CHAIN_IDS3[CHAIN_ID];
10996
+ const targetChainId = EVM_CHAIN_IDS4[CHAIN_ID];
10954
10997
  if (!targetChainId) return;
10955
10998
  if (walletChainId !== void 0 && walletChainId !== targetChainId) {
10956
10999
  if (!switchChain) {