@avalabs/avacloud-waas-react 1.0.10 → 1.0.14-nightly.20250704
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/README.md +181 -37
- package/dist/index.d.mts +105 -4
- package/dist/index.d.ts +105 -4
- package/dist/index.js +466 -2
- package/dist/index.mjs +455 -2
- package/package.json +15 -10
package/dist/index.mjs
CHANGED
|
@@ -1554,7 +1554,7 @@ var queryClient = new QueryClient({
|
|
|
1554
1554
|
}
|
|
1555
1555
|
});
|
|
1556
1556
|
function getCubistEnv(environment) {
|
|
1557
|
-
return environment === "
|
|
1557
|
+
return environment === "production" ? envs.prod : envs.gamma;
|
|
1558
1558
|
}
|
|
1559
1559
|
function ViemProviderWrapper({ children, chainId }) {
|
|
1560
1560
|
const { data: blockchain } = useBlockchain(chainId.toString());
|
|
@@ -1581,6 +1581,10 @@ function AvaCloudWalletProvider({
|
|
|
1581
1581
|
onAuthError,
|
|
1582
1582
|
onWalletUpdate
|
|
1583
1583
|
}) {
|
|
1584
|
+
const { setChainId } = useChainId();
|
|
1585
|
+
useEffect5(() => {
|
|
1586
|
+
setChainId(chainId);
|
|
1587
|
+
}, [chainId, setChainId]);
|
|
1584
1588
|
const authServiceUrl = env === "development" ? "http://localhost:3000" : env === "staging" ? "https://ac-auth-service-env-staging-ava-labs.vercel.app" : "https://ac-auth-service.vercel.app";
|
|
1585
1589
|
const environment = env;
|
|
1586
1590
|
const [isAuthenticated, setIsAuthenticated] = useState7(false);
|
|
@@ -1646,7 +1650,7 @@ function AvaCloudWalletProvider({
|
|
|
1646
1650
|
}
|
|
1647
1651
|
try {
|
|
1648
1652
|
const resp = await CubeSignerClient.createOidcSession(
|
|
1649
|
-
getCubistEnv(environment),
|
|
1653
|
+
getCubistEnv(environment === "production" ? "prod" : "gamma"),
|
|
1650
1654
|
orgConfig.walletProviderOrgID,
|
|
1651
1655
|
accessToken,
|
|
1652
1656
|
["sign:*", "manage:*", "export:*"],
|
|
@@ -4556,9 +4560,454 @@ function useUserWallets() {
|
|
|
4556
4560
|
isLoading
|
|
4557
4561
|
};
|
|
4558
4562
|
}
|
|
4563
|
+
|
|
4564
|
+
// src/wagmi/connector.ts
|
|
4565
|
+
import {
|
|
4566
|
+
createConnector
|
|
4567
|
+
} from "@wagmi/core";
|
|
4568
|
+
import {
|
|
4569
|
+
getAddress
|
|
4570
|
+
} from "viem";
|
|
4571
|
+
function avaCloudWallet() {
|
|
4572
|
+
return createConnector((config) => ({
|
|
4573
|
+
id: "avaCloudWallet",
|
|
4574
|
+
name: "AvaCloud Wallet",
|
|
4575
|
+
type: "injected",
|
|
4576
|
+
async connect() {
|
|
4577
|
+
const { walletClient } = useViem();
|
|
4578
|
+
if (!walletClient) {
|
|
4579
|
+
throw new Error("AvaCloud Wallet not connected");
|
|
4580
|
+
}
|
|
4581
|
+
const accounts = await this.getAccounts();
|
|
4582
|
+
const chainId = await this.getChainId();
|
|
4583
|
+
config.emitter.emit("connect", { accounts, chainId });
|
|
4584
|
+
return { accounts, chainId };
|
|
4585
|
+
},
|
|
4586
|
+
async disconnect() {
|
|
4587
|
+
config.emitter.emit("disconnect");
|
|
4588
|
+
},
|
|
4589
|
+
async getAccounts() {
|
|
4590
|
+
const { walletClient } = useViem();
|
|
4591
|
+
if (!(walletClient == null ? void 0 : walletClient.account)) {
|
|
4592
|
+
throw new Error("AvaCloud Wallet not connected or account not found.");
|
|
4593
|
+
}
|
|
4594
|
+
return [walletClient.account.address];
|
|
4595
|
+
},
|
|
4596
|
+
async getChainId() {
|
|
4597
|
+
const { chainId } = useViem();
|
|
4598
|
+
return chainId;
|
|
4599
|
+
},
|
|
4600
|
+
async getProvider() {
|
|
4601
|
+
const { publicClient } = useViem();
|
|
4602
|
+
if (!publicClient) {
|
|
4603
|
+
throw new Error("Public client not found.");
|
|
4604
|
+
}
|
|
4605
|
+
return publicClient;
|
|
4606
|
+
},
|
|
4607
|
+
async isAuthorized() {
|
|
4608
|
+
const { walletClient } = useViem();
|
|
4609
|
+
return !!walletClient;
|
|
4610
|
+
},
|
|
4611
|
+
onAccountsChanged(accounts) {
|
|
4612
|
+
if (accounts.length === 0) {
|
|
4613
|
+
this.disconnect();
|
|
4614
|
+
} else {
|
|
4615
|
+
config.emitter.emit("change", {
|
|
4616
|
+
accounts: accounts.map((x) => getAddress(x))
|
|
4617
|
+
});
|
|
4618
|
+
}
|
|
4619
|
+
},
|
|
4620
|
+
onChainChanged(chain) {
|
|
4621
|
+
const chainId = Number(chain);
|
|
4622
|
+
config.emitter.emit("change", { chainId });
|
|
4623
|
+
},
|
|
4624
|
+
onDisconnect() {
|
|
4625
|
+
config.emitter.emit("disconnect");
|
|
4626
|
+
}
|
|
4627
|
+
}));
|
|
4628
|
+
}
|
|
4629
|
+
|
|
4630
|
+
// src/providers/GaslessProvider.tsx
|
|
4631
|
+
import { createContext as createContext5, useContext as useContext5, useEffect as useEffect7, useState as useState21 } from "react";
|
|
4632
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
4633
|
+
function validateGaslessConfig(config) {
|
|
4634
|
+
if (!config || typeof config !== "object") {
|
|
4635
|
+
return "Invalid gasless configuration: expected an object";
|
|
4636
|
+
}
|
|
4637
|
+
const requiredFields = [
|
|
4638
|
+
{ field: "relayerUrl", description: "Relayer RPC URL" },
|
|
4639
|
+
{ field: "subnetRpcUrl", description: "Subnet RPC URL" },
|
|
4640
|
+
{ field: "forwarderAddress", description: "Forwarder contract address" },
|
|
4641
|
+
{ field: "domainName", description: "EIP-712 domain name" },
|
|
4642
|
+
{ field: "domainVersion", description: "EIP-712 domain version" },
|
|
4643
|
+
{ field: "requestType", description: "Request type name" }
|
|
4644
|
+
];
|
|
4645
|
+
const missingFields = requiredFields.filter(({ field }) => !config[field]);
|
|
4646
|
+
if (missingFields.length > 0) {
|
|
4647
|
+
const missing = missingFields.map(({ field, description }) => `${field} (${description})`).join(", ");
|
|
4648
|
+
return `Missing required gasless configuration fields: ${missing}`;
|
|
4649
|
+
}
|
|
4650
|
+
try {
|
|
4651
|
+
new URL(config.relayerUrl);
|
|
4652
|
+
} catch (e) {
|
|
4653
|
+
return `Invalid relayer URL format: ${config.relayerUrl}`;
|
|
4654
|
+
}
|
|
4655
|
+
try {
|
|
4656
|
+
new URL(config.subnetRpcUrl);
|
|
4657
|
+
} catch (e) {
|
|
4658
|
+
return `Invalid subnet RPC URL format: ${config.subnetRpcUrl}`;
|
|
4659
|
+
}
|
|
4660
|
+
if (!config.forwarderAddress.match(/^0x[a-fA-F0-9]{40}$/)) {
|
|
4661
|
+
return `Invalid forwarder address format: ${config.forwarderAddress}. Expected a valid Ethereum address.`;
|
|
4662
|
+
}
|
|
4663
|
+
return null;
|
|
4664
|
+
}
|
|
4665
|
+
var GaslessContext = createContext5(null);
|
|
4666
|
+
function GaslessProvider({ children, config, fetchParams }) {
|
|
4667
|
+
const [state, setState] = useState21({
|
|
4668
|
+
isLoading: false,
|
|
4669
|
+
error: null,
|
|
4670
|
+
config: null
|
|
4671
|
+
});
|
|
4672
|
+
const { authServiceUrl, environment } = useAvaCloudWallet();
|
|
4673
|
+
useEffect7(() => {
|
|
4674
|
+
if (config) {
|
|
4675
|
+
const validationError = validateGaslessConfig(config);
|
|
4676
|
+
if (validationError) {
|
|
4677
|
+
setState({
|
|
4678
|
+
isLoading: false,
|
|
4679
|
+
error: new Error(validationError),
|
|
4680
|
+
config: null
|
|
4681
|
+
});
|
|
4682
|
+
} else {
|
|
4683
|
+
setState({ isLoading: false, error: null, config });
|
|
4684
|
+
}
|
|
4685
|
+
return;
|
|
4686
|
+
}
|
|
4687
|
+
if (!fetchParams) {
|
|
4688
|
+
setState({
|
|
4689
|
+
isLoading: false,
|
|
4690
|
+
error: new Error(
|
|
4691
|
+
"GaslessProvider requires either a `config` prop or `fetchParams` prop. Please provide pre-fetched configuration or parameters to fetch it."
|
|
4692
|
+
),
|
|
4693
|
+
config: null
|
|
4694
|
+
});
|
|
4695
|
+
return;
|
|
4696
|
+
}
|
|
4697
|
+
const { orgId, subnetId } = fetchParams;
|
|
4698
|
+
if (!orgId || !subnetId) {
|
|
4699
|
+
setState({
|
|
4700
|
+
isLoading: false,
|
|
4701
|
+
error: new Error(
|
|
4702
|
+
`Invalid fetchParams: both orgId and subnetId are required. Received: orgId="${orgId}", subnetId="${subnetId}"`
|
|
4703
|
+
),
|
|
4704
|
+
config: null
|
|
4705
|
+
});
|
|
4706
|
+
return;
|
|
4707
|
+
}
|
|
4708
|
+
const fetchConfig = async () => {
|
|
4709
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
4710
|
+
try {
|
|
4711
|
+
const url = `${authServiceUrl}/api/gasless-config?orgId=${encodeURIComponent(
|
|
4712
|
+
orgId
|
|
4713
|
+
)}&subnetId=${encodeURIComponent(subnetId)}&environment=${environment}`;
|
|
4714
|
+
const resp = await fetch(url);
|
|
4715
|
+
if (!resp.ok) {
|
|
4716
|
+
let errorMessage = `Failed to fetch gasless configuration (HTTP ${resp.status})`;
|
|
4717
|
+
try {
|
|
4718
|
+
const errorData = await resp.json();
|
|
4719
|
+
if (errorData.error) {
|
|
4720
|
+
errorMessage = errorData.error;
|
|
4721
|
+
if (errorData.details) {
|
|
4722
|
+
errorMessage += `: ${errorData.details}`;
|
|
4723
|
+
}
|
|
4724
|
+
}
|
|
4725
|
+
} catch (e) {
|
|
4726
|
+
if (resp.status === 404) {
|
|
4727
|
+
errorMessage = "Gas relayer configuration not found. Please ensure the gas relayer is set up for your organization and subnet in AvaCloud.";
|
|
4728
|
+
} else if (resp.status === 400) {
|
|
4729
|
+
errorMessage = "Invalid request parameters. Please check your orgId and subnetId.";
|
|
4730
|
+
} else if (resp.status === 500) {
|
|
4731
|
+
errorMessage = "Server error while fetching gasless configuration. Please try again later or contact support.";
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
throw new Error(errorMessage);
|
|
4735
|
+
}
|
|
4736
|
+
const cfg = await resp.json();
|
|
4737
|
+
const validationError = validateGaslessConfig(cfg);
|
|
4738
|
+
if (validationError) {
|
|
4739
|
+
throw new Error(
|
|
4740
|
+
`Invalid gasless configuration received from server: ${validationError}. This may indicate an issue with your AvaCloud gas relayer setup.`
|
|
4741
|
+
);
|
|
4742
|
+
}
|
|
4743
|
+
setState({ isLoading: false, error: null, config: cfg });
|
|
4744
|
+
} catch (err) {
|
|
4745
|
+
let error;
|
|
4746
|
+
if (err instanceof Error) {
|
|
4747
|
+
error = err;
|
|
4748
|
+
} else if (err && typeof err === "object" && "message" in err) {
|
|
4749
|
+
error = new Error(String(err.message));
|
|
4750
|
+
} else {
|
|
4751
|
+
error = new Error("An unexpected error occurred while fetching gasless configuration");
|
|
4752
|
+
}
|
|
4753
|
+
setState({ isLoading: false, error, config: null });
|
|
4754
|
+
}
|
|
4755
|
+
};
|
|
4756
|
+
fetchConfig();
|
|
4757
|
+
}, [config, fetchParams, authServiceUrl, environment]);
|
|
4758
|
+
return /* @__PURE__ */ jsx24(GaslessContext.Provider, { value: state, children });
|
|
4759
|
+
}
|
|
4760
|
+
|
|
4761
|
+
// src/hooks/useGaslessTransaction.ts
|
|
4762
|
+
import { useCallback as useCallback11, useState as useState22 } from "react";
|
|
4763
|
+
import * as ethers from "ethers";
|
|
4764
|
+
import axios from "axios";
|
|
4765
|
+
import { Secp256k1 as Secp256k14 } from "@cubist-labs/cubesigner-sdk";
|
|
4766
|
+
var FORWARDER_GET_NONCE_ABI = [
|
|
4767
|
+
{
|
|
4768
|
+
inputs: [
|
|
4769
|
+
{
|
|
4770
|
+
internalType: "address",
|
|
4771
|
+
name: "from",
|
|
4772
|
+
type: "address"
|
|
4773
|
+
}
|
|
4774
|
+
],
|
|
4775
|
+
name: "getNonce",
|
|
4776
|
+
outputs: [
|
|
4777
|
+
{
|
|
4778
|
+
internalType: "uint256",
|
|
4779
|
+
name: "",
|
|
4780
|
+
type: "uint256"
|
|
4781
|
+
}
|
|
4782
|
+
],
|
|
4783
|
+
stateMutability: "view",
|
|
4784
|
+
type: "function"
|
|
4785
|
+
}
|
|
4786
|
+
];
|
|
4787
|
+
function useGaslessTransaction({ gaslessConfig, contractAddress: defaultContractAddress, abi: defaultAbi }) {
|
|
4788
|
+
const [state, setState] = useState22({
|
|
4789
|
+
isLoading: false,
|
|
4790
|
+
error: null,
|
|
4791
|
+
txHash: null
|
|
4792
|
+
});
|
|
4793
|
+
const config = gaslessConfig;
|
|
4794
|
+
const { wallet, cubistClient } = useAvaCloudWallet();
|
|
4795
|
+
useViem();
|
|
4796
|
+
const reset = useCallback11(() => {
|
|
4797
|
+
setState({
|
|
4798
|
+
isLoading: false,
|
|
4799
|
+
error: null,
|
|
4800
|
+
txHash: null
|
|
4801
|
+
});
|
|
4802
|
+
}, []);
|
|
4803
|
+
const validateConfig = useCallback11((config2) => {
|
|
4804
|
+
if (!config2) {
|
|
4805
|
+
return "Gasless configuration is not available. Please ensure GaslessProvider is properly configured.";
|
|
4806
|
+
}
|
|
4807
|
+
const requiredFields = [
|
|
4808
|
+
{ field: "relayerUrl", description: "Relayer RPC URL" },
|
|
4809
|
+
{ field: "subnetRpcUrl", description: "Subnet RPC URL" },
|
|
4810
|
+
{ field: "forwarderAddress", description: "Forwarder contract address" },
|
|
4811
|
+
{ field: "domainName", description: "EIP-712 domain name" },
|
|
4812
|
+
{ field: "domainVersion", description: "EIP-712 domain version" }
|
|
4813
|
+
];
|
|
4814
|
+
if (!config2.requestType) {
|
|
4815
|
+
config2.requestType = "Message";
|
|
4816
|
+
}
|
|
4817
|
+
for (const { field, description } of requiredFields) {
|
|
4818
|
+
if (!config2[field]) {
|
|
4819
|
+
return `Missing required gasless configuration field: ${field} (${description}). Please check your AvaCloud gas relayer setup.`;
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
try {
|
|
4823
|
+
new URL(config2.relayerUrl);
|
|
4824
|
+
} catch (e) {
|
|
4825
|
+
return `Invalid relayer URL: ${config2.relayerUrl}. Expected a valid HTTP/HTTPS URL.`;
|
|
4826
|
+
}
|
|
4827
|
+
try {
|
|
4828
|
+
new URL(config2.subnetRpcUrl);
|
|
4829
|
+
} catch (e) {
|
|
4830
|
+
return `Invalid subnet RPC URL: ${config2.subnetRpcUrl}. Expected a valid HTTP/HTTPS URL.`;
|
|
4831
|
+
}
|
|
4832
|
+
if (!config2.forwarderAddress.match(/^0x[a-fA-F0-9]{40}$/)) {
|
|
4833
|
+
return `Invalid forwarder address: ${config2.forwarderAddress}. Expected a valid Ethereum address.`;
|
|
4834
|
+
}
|
|
4835
|
+
return null;
|
|
4836
|
+
}, []);
|
|
4837
|
+
const sendGaslessTransaction = useCallback11(async ({
|
|
4838
|
+
functionName,
|
|
4839
|
+
args = [],
|
|
4840
|
+
abi: overrideAbi,
|
|
4841
|
+
contractAddress: overrideContractAddress
|
|
4842
|
+
}) => {
|
|
4843
|
+
const contractAddress = overrideContractAddress != null ? overrideContractAddress : defaultContractAddress;
|
|
4844
|
+
const abi = overrideAbi != null ? overrideAbi : defaultAbi;
|
|
4845
|
+
if (!contractAddress || !abi) {
|
|
4846
|
+
setState((prev) => ({ ...prev, error: "Contract address and ABI are required. Please provide them either when initializing the hook or when calling sendGaslessTransaction." }));
|
|
4847
|
+
return;
|
|
4848
|
+
}
|
|
4849
|
+
const configError = validateConfig(config);
|
|
4850
|
+
if (configError) {
|
|
4851
|
+
setState((prev) => ({ ...prev, error: configError }));
|
|
4852
|
+
return;
|
|
4853
|
+
}
|
|
4854
|
+
if (!config) {
|
|
4855
|
+
setState((prev) => ({
|
|
4856
|
+
...prev,
|
|
4857
|
+
error: "Gasless configuration is not available. Please ensure you pass a valid config object when initializing useGaslessTransaction."
|
|
4858
|
+
}));
|
|
4859
|
+
return;
|
|
4860
|
+
}
|
|
4861
|
+
if (!(wallet == null ? void 0 : wallet.address)) {
|
|
4862
|
+
setState((prev) => ({ ...prev, error: "Wallet not connected. Please connect your wallet before sending transactions." }));
|
|
4863
|
+
return;
|
|
4864
|
+
}
|
|
4865
|
+
if (!cubistClient) {
|
|
4866
|
+
setState((prev) => ({ ...prev, error: "Authentication client not initialized. Please ensure you are properly authenticated." }));
|
|
4867
|
+
return;
|
|
4868
|
+
}
|
|
4869
|
+
if (!contractAddress.match(/^0x[a-fA-F0-9]{40}$/)) {
|
|
4870
|
+
setState((prev) => ({ ...prev, error: `Invalid contract address: ${contractAddress}. Expected a valid Ethereum address.` }));
|
|
4871
|
+
return;
|
|
4872
|
+
}
|
|
4873
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
4874
|
+
try {
|
|
4875
|
+
const provider = new ethers.providers.JsonRpcProvider(config.subnetRpcUrl);
|
|
4876
|
+
const forwarder = new ethers.Contract(config.forwarderAddress, FORWARDER_GET_NONCE_ABI, provider);
|
|
4877
|
+
const targetContract = new ethers.Contract(contractAddress, abi, provider);
|
|
4878
|
+
const gas = await targetContract.estimateGas[functionName](...args);
|
|
4879
|
+
const forwarderNonce = await forwarder.getNonce(wallet.address);
|
|
4880
|
+
const data = targetContract.interface.encodeFunctionData(functionName, args);
|
|
4881
|
+
const types = {
|
|
4882
|
+
EIP712Domain: [
|
|
4883
|
+
{ name: "name", type: "string" },
|
|
4884
|
+
{ name: "version", type: "string" },
|
|
4885
|
+
{ name: "chainId", type: "uint256" },
|
|
4886
|
+
{ name: "verifyingContract", type: "address" }
|
|
4887
|
+
],
|
|
4888
|
+
[config.requestType]: [
|
|
4889
|
+
{ name: "from", type: "address" },
|
|
4890
|
+
{ name: "to", type: "address" },
|
|
4891
|
+
{ name: "value", type: "uint256" },
|
|
4892
|
+
{ name: "gas", type: "uint256" },
|
|
4893
|
+
{ name: "nonce", type: "uint256" },
|
|
4894
|
+
{ name: "data", type: "bytes" },
|
|
4895
|
+
{ name: "validUntilTime", type: "uint256" }
|
|
4896
|
+
]
|
|
4897
|
+
};
|
|
4898
|
+
if (config.suffix) {
|
|
4899
|
+
const suffixParts = config.suffix.match(/^(\w+)\s+(.+)\)$/);
|
|
4900
|
+
if (suffixParts) {
|
|
4901
|
+
const [, suffixType, suffixName] = suffixParts;
|
|
4902
|
+
types[config.requestType].push({
|
|
4903
|
+
name: suffixName,
|
|
4904
|
+
type: suffixType
|
|
4905
|
+
});
|
|
4906
|
+
}
|
|
4907
|
+
}
|
|
4908
|
+
const nonceHex = forwarderNonce.toHexString();
|
|
4909
|
+
const message = {
|
|
4910
|
+
from: wallet.address,
|
|
4911
|
+
to: contractAddress,
|
|
4912
|
+
value: "0x0",
|
|
4913
|
+
gas: gas.toHexString(),
|
|
4914
|
+
nonce: nonceHex,
|
|
4915
|
+
data,
|
|
4916
|
+
validUntilTime: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
|
4917
|
+
};
|
|
4918
|
+
if (config.suffix) {
|
|
4919
|
+
const suffixParts = config.suffix.match(/^(\w+)\s+(.+)\)$/);
|
|
4920
|
+
if (suffixParts) {
|
|
4921
|
+
const [, , suffixName] = suffixParts;
|
|
4922
|
+
message[suffixName] = Buffer.from(config.suffix, "utf8");
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
const domain = {
|
|
4926
|
+
name: config.domainName,
|
|
4927
|
+
version: config.domainVersion,
|
|
4928
|
+
chainId: (await provider.getNetwork()).chainId,
|
|
4929
|
+
verifyingContract: config.forwarderAddress
|
|
4930
|
+
};
|
|
4931
|
+
const digest = ethers.utils._TypedDataEncoder.hash(domain, {
|
|
4932
|
+
[config.requestType]: types[config.requestType]
|
|
4933
|
+
}, message);
|
|
4934
|
+
const key = await cubistClient.org().getKeyByMaterialId(Secp256k14.Evm, wallet.address);
|
|
4935
|
+
const sigResp = await key.signBlob({
|
|
4936
|
+
message_base64: Buffer.from(digest.slice(2), "hex").toString("base64")
|
|
4937
|
+
});
|
|
4938
|
+
const signatureData = sigResp.data().signature;
|
|
4939
|
+
const signature = signatureData.startsWith("0x") ? signatureData : `0x${signatureData}`;
|
|
4940
|
+
const typedRequest = {
|
|
4941
|
+
domain,
|
|
4942
|
+
types: {
|
|
4943
|
+
[config.requestType]: types[config.requestType]
|
|
4944
|
+
},
|
|
4945
|
+
primaryType: config.requestType,
|
|
4946
|
+
message
|
|
4947
|
+
};
|
|
4948
|
+
const txPayload = {
|
|
4949
|
+
forwardRequest: typedRequest,
|
|
4950
|
+
metadata: {
|
|
4951
|
+
signature: signature.substring(2)
|
|
4952
|
+
// strip 0x
|
|
4953
|
+
}
|
|
4954
|
+
};
|
|
4955
|
+
const rawTx = "0x" + Buffer.from(JSON.stringify(txPayload), "utf8").toString("hex");
|
|
4956
|
+
const requestBody = {
|
|
4957
|
+
id: 1,
|
|
4958
|
+
jsonrpc: "2.0",
|
|
4959
|
+
method: "eth_sendRawTransaction",
|
|
4960
|
+
params: [rawTx]
|
|
4961
|
+
};
|
|
4962
|
+
const resp = await axios.post(config.relayerUrl, requestBody, {
|
|
4963
|
+
headers: {
|
|
4964
|
+
"Content-Type": "application/json"
|
|
4965
|
+
}
|
|
4966
|
+
});
|
|
4967
|
+
const txHash = resp.data.result;
|
|
4968
|
+
setState((prev) => ({ ...prev, txHash }));
|
|
4969
|
+
await provider.waitForTransaction(txHash);
|
|
4970
|
+
} catch (err) {
|
|
4971
|
+
let errorMessage = "Failed to send gasless transaction";
|
|
4972
|
+
if (err instanceof Error) {
|
|
4973
|
+
if (err.message.includes("estimateGas")) {
|
|
4974
|
+
errorMessage = `Failed to estimate gas for function "${functionName}". Please verify the function exists and parameters are correct.`;
|
|
4975
|
+
} else if (err.message.includes("getNonce")) {
|
|
4976
|
+
errorMessage = "Failed to fetch nonce from forwarder contract. Please verify the forwarder address is correct and deployed.";
|
|
4977
|
+
} else if (err.message.includes("getKeyByMaterialId")) {
|
|
4978
|
+
errorMessage = "Failed to retrieve signing key. Please ensure your wallet is properly initialized.";
|
|
4979
|
+
} else if (err.message.includes("signBlob")) {
|
|
4980
|
+
errorMessage = "Failed to sign transaction. Please check your authentication status.";
|
|
4981
|
+
} else if (err.message.includes("Network Error") || err.message.includes("ECONNREFUSED")) {
|
|
4982
|
+
errorMessage = "Network error: Unable to connect to relayer service. Please check your internet connection and relayer URL.";
|
|
4983
|
+
} else if (err.message.includes("404")) {
|
|
4984
|
+
errorMessage = "Relayer endpoint not found. Please verify the relayer URL is correct.";
|
|
4985
|
+
} else if (err.message.includes("500") || err.message.includes("502") || err.message.includes("503")) {
|
|
4986
|
+
errorMessage = "Relayer service error. The gas relayer service may be temporarily unavailable.";
|
|
4987
|
+
} else if (err.message.includes("insufficient funds")) {
|
|
4988
|
+
errorMessage = "The relayer has insufficient funds to sponsor this transaction. Please contact support.";
|
|
4989
|
+
} else {
|
|
4990
|
+
errorMessage = `Transaction failed: ${err.message}`;
|
|
4991
|
+
}
|
|
4992
|
+
}
|
|
4993
|
+
setState((prev) => ({
|
|
4994
|
+
...prev,
|
|
4995
|
+
error: errorMessage
|
|
4996
|
+
}));
|
|
4997
|
+
} finally {
|
|
4998
|
+
setState((prev) => ({ ...prev, isLoading: false }));
|
|
4999
|
+
}
|
|
5000
|
+
}, [config, wallet == null ? void 0 : wallet.address, cubistClient, validateConfig, defaultAbi, defaultContractAddress]);
|
|
5001
|
+
return {
|
|
5002
|
+
...state,
|
|
5003
|
+
sendGaslessTransaction,
|
|
5004
|
+
reset
|
|
5005
|
+
};
|
|
5006
|
+
}
|
|
4559
5007
|
export {
|
|
4560
5008
|
AvaCloudWalletProvider,
|
|
4561
5009
|
ExportView,
|
|
5010
|
+
GaslessProvider,
|
|
4562
5011
|
LoginButton,
|
|
4563
5012
|
ReceiveView,
|
|
4564
5013
|
SendView,
|
|
@@ -4569,9 +5018,13 @@ export {
|
|
|
4569
5018
|
WalletButton,
|
|
4570
5019
|
WalletCard,
|
|
4571
5020
|
WalletDisplay,
|
|
5021
|
+
avaCloudWallet,
|
|
4572
5022
|
useAuth,
|
|
4573
5023
|
useAvaCloudWallet,
|
|
5024
|
+
useBlockchain,
|
|
4574
5025
|
useChainId,
|
|
5026
|
+
useGaslessTransaction,
|
|
5027
|
+
useGlacier,
|
|
4575
5028
|
usePostMessage,
|
|
4576
5029
|
useSignMessage,
|
|
4577
5030
|
useSignTransaction,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avalabs/avacloud-waas-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14-nightly.20250704",
|
|
4
4
|
"description": "React SDK for AvaCloud Wallet as a Service",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -10,8 +10,16 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/**"
|
|
12
12
|
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --external react && cp -r public/* dist/",
|
|
15
|
+
"dev": "tsup src/index.ts --format esm,cjs --watch --dts --external react",
|
|
16
|
+
"lint": "eslint \"src/**/*.ts*\"",
|
|
17
|
+
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
13
20
|
"devDependencies": {
|
|
14
21
|
"@iconify/types": "^2.0.0",
|
|
22
|
+
"@types/node": "^20.9.0",
|
|
15
23
|
"@types/react": "^18.2.46",
|
|
16
24
|
"@types/react-dom": "^18.2.18",
|
|
17
25
|
"eslint": "^8.53.0",
|
|
@@ -28,9 +36,12 @@
|
|
|
28
36
|
"@cubist-labs/cubesigner-sdk": "0.4.110-0",
|
|
29
37
|
"@iconify/react": "^4.1.1",
|
|
30
38
|
"@tanstack/react-query": "^5.64.2",
|
|
39
|
+
"@wagmi/core": "^2.17.3",
|
|
31
40
|
"lottie-react": "^2.4.0",
|
|
32
41
|
"qrcode.react": "^3.1.0",
|
|
33
|
-
"viem": "
|
|
42
|
+
"viem": "2.31.2",
|
|
43
|
+
"ethers": "^5.7.2",
|
|
44
|
+
"axios": "^1.6.0"
|
|
34
45
|
},
|
|
35
46
|
"keywords": [
|
|
36
47
|
"avalanche",
|
|
@@ -49,11 +60,5 @@
|
|
|
49
60
|
"url": "https://github.com/ava-labs/avacloud-auth-react/issues"
|
|
50
61
|
},
|
|
51
62
|
"homepage": "https://github.com/ava-labs/avacloud-auth-react#readme",
|
|
52
|
-
"author": "Ava Labs, Inc."
|
|
53
|
-
|
|
54
|
-
"build": "tsup src/index.ts --format esm,cjs --dts --external react && cp -r public/* dist/",
|
|
55
|
-
"dev": "tsup src/index.ts --format esm,cjs --watch --dts --external react",
|
|
56
|
-
"lint": "eslint \"src/**/*.ts*\"",
|
|
57
|
-
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
63
|
+
"author": "Ava Labs, Inc."
|
|
64
|
+
}
|