@0xkey-io/react-wallet-kit 0.1.1 → 0.3.0

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.
@@ -35,6 +35,7 @@ var OTP = require('../../components/auth/OTP.js');
35
35
  var RemoveEmail = require('../../components/user/RemoveEmail.js');
36
36
  var RemovePhoneNumber = require('../../components/user/RemovePhoneNumber.js');
37
37
  var Verify = require('../../components/verify/Verify.js');
38
+ var VerifyEnclave = require('../../components/verify/VerifyEnclave.js');
38
39
  var OnRamp = require('../../components/onramp/OnRamp.js');
39
40
  var Svg = require('../../components/design/Svg.js');
40
41
  var SendTransaction = require('../../components/send-transaction/SendTransaction.js');
@@ -1765,6 +1766,14 @@ const ClientProvider = ({
1765
1766
  if (!client) throw new sdkTypes.ZeroXKeyError("Client is not initialized.", sdkTypes.ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
1766
1767
  return utils.withZeroXKeyErrorHandling(() => client.fetchBootProofForAppProof(params), () => logout(), callbacks, "Failed to fetch or create delegated access user");
1767
1768
  }, [client, callbacks, logout]);
1769
+ const fetchLatestBootProof = react.useCallback(async params => {
1770
+ if (!client) throw new sdkTypes.ZeroXKeyError("Client is not initialized.", sdkTypes.ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
1771
+ return utils.withZeroXKeyErrorHandling(() => client.fetchLatestBootProof(params), () => logout(), callbacks, "Failed to get the latest boot proof");
1772
+ }, [client, callbacks, logout]);
1773
+ const verifyLatestBootProof = react.useCallback(async params => {
1774
+ if (!client) throw new sdkTypes.ZeroXKeyError("Client is not initialized.", sdkTypes.ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
1775
+ return utils.withZeroXKeyErrorHandling(() => client.verifyLatestBootProof(params), () => logout(), callbacks, "Failed to verify the latest boot proof");
1776
+ }, [client, callbacks, logout]);
1768
1777
  const verifyAppProofs = react.useCallback(async params => {
1769
1778
  if (!client) throw new sdkTypes.ZeroXKeyError("Client is not initialized.", sdkTypes.ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
1770
1779
  return utils.withZeroXKeyErrorHandling(() => client.verifyAppProofs(params), () => logout(), callbacks, "Failed to verify app proofs");
@@ -3516,48 +3525,39 @@ const ClientProvider = ({
3516
3525
  urlForSignature,
3517
3526
  countryCode,
3518
3527
  onrampProvider = "FIAT_ON_RAMP_PROVIDER_MOONPAY",
3519
- sandboxMode = true,
3520
3528
  successPageDuration = 2000,
3521
- openInNewTab = false
3529
+ openInNewTab = false,
3530
+ openMode,
3531
+ polling,
3532
+ onStatusChange
3522
3533
  } = params;
3534
+ if (params.sandboxMode === undefined) {
3535
+ throw new core.OnRampError(core.OnRampErrorCode.SANDBOX_MODE_REQUIRED, "sandboxMode must be explicitly set for on-ramp flows.");
3536
+ }
3537
+ // Fail fast (before opening any modal/window) when the provider has no
3538
+ // supported runtime, so callers get a typed error instead of a popup.
3539
+ core.assertOnRampProviderSupported(onrampProvider);
3540
+ if (!client?.httpClient) {
3541
+ throw new sdkTypes.ZeroXKeyError("Client is not initialized.", sdkTypes.ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
3542
+ }
3523
3543
  const s = await getSession();
3524
3544
  const organizationId = params?.organizationId || s?.organizationId;
3525
3545
  if (!organizationId) {
3526
3546
  throw new sdkTypes.ZeroXKeyError("A session or passed in organization ID is required.", sdkTypes.ZeroXKeyErrorCodes.INVALID_REQUEST);
3527
3547
  }
3528
- let cryptoCurrencyCode;
3529
- let network;
3530
- switch (true) {
3531
- case walletAccount.addressFormat === "ADDRESS_FORMAT_ETHEREUM":
3532
- cryptoCurrencyCode = sdkTypes.FiatOnRampCryptoCurrency.ETHEREUM;
3533
- network = sdkTypes.FiatOnRampBlockchainNetwork.ETHEREUM;
3534
- break;
3535
- case walletAccount.addressFormat?.includes("ADDRESS_FORMAT_BITCOIN"):
3536
- cryptoCurrencyCode = sdkTypes.FiatOnRampCryptoCurrency.BITCOIN;
3537
- network = sdkTypes.FiatOnRampBlockchainNetwork.BITCOIN;
3538
- break;
3539
- case walletAccount.addressFormat === "ADDRESS_FORMAT_SOLANA":
3540
- cryptoCurrencyCode = sdkTypes.FiatOnRampCryptoCurrency.SOLANA;
3541
- network = sdkTypes.FiatOnRampBlockchainNetwork.SOLANA;
3542
- break;
3543
- default:
3544
- cryptoCurrencyCode = sdkTypes.FiatOnRampCryptoCurrency.ETHEREUM;
3545
- network = sdkTypes.FiatOnRampBlockchainNetwork.ETHEREUM;
3546
- break;
3547
- }
3548
- const openNewTab = openInNewTab || isMobile;
3549
- cryptoCurrencyCode = params.cryptoCurrencyCode || cryptoCurrencyCode;
3550
- network = params.network || network;
3548
+ const inferredAsset = params.network && params.cryptoCurrencyCode ? undefined : core.inferOnRampAssetFromWalletAccount(walletAccount);
3549
+ const cryptoCurrencyCode = params.cryptoCurrencyCode ?? inferredAsset?.cryptoCurrencyCode;
3550
+ const network = params.network ?? inferredAsset?.network;
3551
+ if (!cryptoCurrencyCode || !network) {
3552
+ throw new core.OnRampError(core.OnRampErrorCode.ASSET_REQUIRED, "network and cryptoCurrencyCode are required for on-ramp flows.");
3553
+ }
3554
+ const resolvedOpenMode = openMode ?? (openInNewTab || isMobile ? "newTab" : "popup");
3551
3555
  return new Promise((resolve, reject) => {
3552
3556
  const OnRampContainer = () => {
3553
3557
  const [completed, setCompleted] = react.useState(false);
3554
- const pollingRef = react.useRef(null);
3555
- const cleanup = () => {
3556
- if (pollingRef.current) {
3557
- clearInterval(pollingRef.current);
3558
- pollingRef.current = null;
3559
- }
3560
- };
3558
+ const [result, setResult] = react.useState();
3559
+ const abortRef = react.useRef(null);
3560
+ const cleanup = () => abortRef.current?.abort();
3561
3561
  react.useEffect(() => {
3562
3562
  return () => {
3563
3563
  cleanup();
@@ -3566,17 +3566,21 @@ const ClientProvider = ({
3566
3566
  const action = async () => {
3567
3567
  try {
3568
3568
  let onRampWindow = null;
3569
- if (openNewTab) {
3569
+ if (resolvedOpenMode === "newTab") {
3570
3570
  onRampWindow = window.open("", "_blank");
3571
- if (!onRampWindow) throw new Error("Failed to open On Ramp tab.");
3571
+ if (!onRampWindow) throw new core.OnRampError(core.OnRampErrorCode.POPUP_BLOCKED, "Failed to open On Ramp tab.");
3572
3572
  }
3573
- const result = await client?.httpClient?.initFiatOnRamp({
3573
+ const initResult = await core.initOnRampFlow({
3574
+ runtimeClient: client.httpClient,
3574
3575
  onrampProvider,
3575
3576
  walletAddress: walletAccount.address,
3576
3577
  network,
3577
3578
  cryptoCurrencyCode,
3578
- sandboxMode,
3579
3579
  organizationId,
3580
+ sandboxMode: params.sandboxMode,
3581
+ ...(params.stampWith ? {
3582
+ stampWith: params.stampWith
3583
+ } : {}),
3580
3584
  ...(fiatCurrencyCode ? {
3581
3585
  fiatCurrencyCode
3582
3586
  } : {}),
@@ -3592,63 +3596,63 @@ const ClientProvider = ({
3592
3596
  ...(countrySubdivisionCode ? {
3593
3597
  countrySubdivisionCode
3594
3598
  } : {}),
3595
- ...(sandboxMode !== undefined ? {
3596
- sandboxMode
3597
- } : {}),
3598
3599
  ...(urlForSignature ? {
3599
3600
  urlForSignature
3600
3601
  } : {})
3601
3602
  });
3602
- if (!result?.onRampUrl) throw new Error("Missing onRampUrl");
3603
- if (openNewTab && onRampWindow) {
3604
- onRampWindow.location.href = result.onRampUrl.toString();
3603
+ onStatusChange?.(initResult);
3604
+ if (resolvedOpenMode === "returnUrl") {
3605
+ setResult(initResult);
3606
+ setCompleted(true);
3607
+ return;
3608
+ }
3609
+ const providerUrl = initResult.signedUrl ?? initResult.onRampUrl;
3610
+ if (resolvedOpenMode === "newTab" && onRampWindow) {
3611
+ onRampWindow.location.href = providerUrl;
3605
3612
  } else {
3606
3613
  const popupWidth = 500;
3607
3614
  const popupHeight = 600;
3608
3615
  const left = window.screenX + (window.innerWidth - popupWidth) / 2;
3609
3616
  const top = window.screenY + (window.innerHeight - popupHeight) / 2;
3610
- onRampWindow = window.open(result.onRampUrl.toString(), "_blank", `width=${popupWidth},height=${popupHeight},top=${top},left=${left},scrollbars=yes,resizable=yes`);
3611
- if (!onRampWindow) throw new Error("Failed to open On Ramp window.");
3617
+ onRampWindow = window.open(providerUrl, "_blank", `width=${popupWidth},height=${popupHeight},top=${top},left=${left},scrollbars=yes,resizable=yes`);
3618
+ if (!onRampWindow) throw new core.OnRampError(core.OnRampErrorCode.POPUP_BLOCKED, "Failed to open On Ramp window.");
3612
3619
  }
3613
- const onRampTransactionId = result.onRampTransactionId;
3614
- if (!onRampTransactionId) throw new Error("No onRampTransactionId returned");
3615
- return new Promise((resolveAction, rejectAction) => {
3616
- pollingRef.current = setInterval(async () => {
3617
- try {
3618
- if (onrampProvider === "FIAT_ON_RAMP_PROVIDER_COINBASE" && onRampWindow?.closed) {
3619
- cleanup();
3620
- rejectAction(new Error("On-ramp popup closed by user"));
3621
- return;
3622
- }
3623
- let currentUrl = "";
3624
- try {
3625
- currentUrl = onRampWindow?.location.href || "";
3626
- } catch {}
3627
- if (currentUrl && currentUrl.startsWith(window.location.origin)) {
3628
- cleanup();
3629
- onRampWindow?.close();
3630
- setCompleted(true);
3631
- resolveAction();
3632
- return;
3633
- }
3634
- const resp = await client?.httpClient?.getOnRampTransactionStatus({
3635
- transactionId: onRampTransactionId,
3636
- refresh: true
3637
- });
3638
- const status = resp?.transactionStatus;
3639
- if (["COMPLETED", "FAILED", "CANCELLED"].includes(status ?? "")) {
3640
- cleanup();
3641
- try {
3642
- onRampWindow?.close();
3643
- } catch {}
3644
- setCompleted(true);
3645
- resolveAction();
3646
- }
3647
- } catch (error) {
3648
- console.warn("Polling error (ignored):", error);
3649
- }
3650
- }, 3000);
3620
+ abortRef.current = new AbortController();
3621
+ const status = await core.pollOnRampTransactionStatus({
3622
+ runtimeClient: client.httpClient,
3623
+ organizationId,
3624
+ transactionId: initResult.onRampTransactionId,
3625
+ refresh: polling?.refresh ?? true,
3626
+ signal: abortRef.current.signal,
3627
+ onStatusUpdate: polledStatus => {
3628
+ onStatusChange?.({
3629
+ ...initResult,
3630
+ status: polledStatus
3631
+ });
3632
+ },
3633
+ ...(params.stampWith ? {
3634
+ stampWith: params.stampWith
3635
+ } : {}),
3636
+ ...(polling?.intervalMs ? {
3637
+ intervalMs: polling.intervalMs
3638
+ } : {}),
3639
+ ...(polling?.timeoutMs ? {
3640
+ timeoutMs: polling.timeoutMs
3641
+ } : {}),
3642
+ ...(polling?.maxConsecutiveErrors ? {
3643
+ maxConsecutiveErrors: polling.maxConsecutiveErrors
3644
+ } : {})
3645
+ });
3646
+ try {
3647
+ onRampWindow?.close();
3648
+ } catch {}
3649
+ // The terminal status was already emitted via onStatusUpdate
3650
+ // inside pollOnRampTransactionStatus; avoid a duplicate callback.
3651
+ setResult({
3652
+ ...initResult,
3653
+ status
3651
3654
  });
3655
+ setCompleted(true);
3652
3656
  } catch (err) {
3653
3657
  cleanup();
3654
3658
  throw err;
@@ -3662,10 +3666,11 @@ const ClientProvider = ({
3662
3666
  }),
3663
3667
  onrampProvider: onrampProvider,
3664
3668
  action: action,
3665
- sandboxMode: sandboxMode,
3669
+ sandboxMode: params.sandboxMode,
3666
3670
  completed: completed,
3671
+ result: result,
3667
3672
  successPageDuration: successPageDuration,
3668
- onSuccess: () => resolve(),
3673
+ onSuccess: resolvedResult => resolve(resolvedResult),
3669
3674
  onError: err => reject(err)
3670
3675
  });
3671
3676
  };
@@ -3674,7 +3679,9 @@ const ClientProvider = ({
3674
3679
  content: jsxRuntime.jsx(OnRampContainer, {}),
3675
3680
  showTitle: false,
3676
3681
  preventBack: true,
3677
- onClose: () => reject(new sdkTypes.ZeroXKeyError("User canceled the onramp process.", sdkTypes.ZeroXKeyErrorCodes.USER_CANCELED))
3682
+ onClose: () => {
3683
+ reject(new core.OnRampError(core.OnRampErrorCode.USER_ABORTED, "User canceled the onramp process."));
3684
+ }
3678
3685
  });
3679
3686
  });
3680
3687
  }, [getSession, client, pushPage]);
@@ -3721,6 +3728,53 @@ const ClientProvider = ({
3721
3728
  throw new sdkTypes.ZeroXKeyError("Failed to verify app proofs.", sdkTypes.ZeroXKeyErrorCodes.VERIFY_APP_PROOFS_ERROR, error);
3722
3729
  }
3723
3730
  }, [getSession, pushPage]);
3731
+ const handleVerifyEnclave = react.useCallback(async params => {
3732
+ const {
3733
+ appName,
3734
+ successPageDuration = 3000,
3735
+ stampWith,
3736
+ anchor
3737
+ } = params || {};
3738
+ const s = await getSession();
3739
+ const organizationId = params?.organizationId || s?.organizationId;
3740
+ if (!organizationId) {
3741
+ throw new sdkTypes.ZeroXKeyError("A session or passed in organization ID is required.", sdkTypes.ZeroXKeyErrorCodes.INVALID_REQUEST);
3742
+ }
3743
+ try {
3744
+ return await new Promise((resolve, reject) => {
3745
+ pushPage({
3746
+ key: "Verify enclave",
3747
+ content: jsxRuntime.jsx(VerifyEnclave.VerifyEnclavePage, {
3748
+ appName: appName,
3749
+ onSuccess: pivotHashHex => {
3750
+ resolve(pivotHashHex);
3751
+ },
3752
+ onError: error => {
3753
+ reject(error);
3754
+ },
3755
+ successPageDuration: successPageDuration,
3756
+ ...(stampWith && {
3757
+ stampWith
3758
+ }),
3759
+ ...(anchor && {
3760
+ anchor
3761
+ }),
3762
+ ...(organizationId !== undefined && {
3763
+ organizationId
3764
+ })
3765
+ }),
3766
+ showTitle: false,
3767
+ preventBack: true,
3768
+ onClose: () => reject(new sdkTypes.ZeroXKeyError("User canceled the verify enclave process.", sdkTypes.ZeroXKeyErrorCodes.USER_CANCELED))
3769
+ });
3770
+ });
3771
+ } catch (error) {
3772
+ if (error instanceof sdkTypes.ZeroXKeyError) {
3773
+ throw error;
3774
+ }
3775
+ throw new sdkTypes.ZeroXKeyError("Failed to verify enclave.", sdkTypes.ZeroXKeyErrorCodes.VERIFY_LATEST_BOOT_PROOF_ERROR, error);
3776
+ }
3777
+ }, [getSession, pushPage]);
3724
3778
  react.useEffect(() => {
3725
3779
  if (proxyAuthConfigRef.current) return;
3726
3780
  // Only fetch the proxy auth config once. Use that to build the master config.
@@ -3896,6 +3950,8 @@ const ClientProvider = ({
3896
3950
  createApiKeyPair,
3897
3951
  getProxyAuthConfig,
3898
3952
  fetchBootProofForAppProof,
3953
+ fetchLatestBootProof,
3954
+ verifyLatestBootProof,
3899
3955
  verifyAppProofs,
3900
3956
  handleLogin,
3901
3957
  handleGoogleOauth,
@@ -3922,6 +3978,7 @@ const ClientProvider = ({
3922
3978
  handleRemoveUserEmail,
3923
3979
  handleRemoveUserPhoneNumber,
3924
3980
  handleVerifyAppProofs,
3981
+ handleVerifyEnclave,
3925
3982
  handleOnRamp,
3926
3983
  handleSendTransaction,
3927
3984
  handleSendErc20Transfer