@satoshai/kit 0.4.1 → 0.5.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { PostCondition, PostConditionMode, ClarityValue } from '@stacks/transactions';
3
+ import { ClarityAbi, ExtractAbiFunctionNames, Pretty, ExtractAbiFunction, ClarityAbiArgToPrimitiveTypeValue } from 'clarity-abitype';
4
+ export { ClarityAbi } from 'clarity-abitype';
3
5
 
4
6
  declare const SUPPORTED_STACKS_WALLETS: readonly ["xverse", "leather", "asigna", "fordefi", "wallet-connect", "okx"];
5
7
  type SupportedStacksWallet = (typeof SUPPORTED_STACKS_WALLETS)[number];
@@ -122,26 +124,82 @@ declare const useSignMessage: () => {
122
124
  status: MutationStatus;
123
125
  };
124
126
 
127
+ interface TransferSTXVariables {
128
+ recipient: string;
129
+ amount: bigint | number | string;
130
+ memo?: string;
131
+ fee?: bigint | number | string;
132
+ nonce?: bigint | number | string;
133
+ }
134
+ interface TransferSTXOptions {
135
+ onSuccess?: (txid: string) => void;
136
+ onError?: (error: Error) => void;
137
+ onSettled?: (txid: string | undefined, error: Error | null) => void;
138
+ }
139
+ declare const useTransferSTX: () => {
140
+ transferSTX: (variables: TransferSTXVariables, options?: TransferSTXOptions) => void;
141
+ transferSTXAsync: (variables: TransferSTXVariables) => Promise<string>;
142
+ reset: () => void;
143
+ data: string | undefined;
144
+ error: Error | null;
145
+ isError: boolean;
146
+ isIdle: boolean;
147
+ isPending: boolean;
148
+ isSuccess: boolean;
149
+ status: MutationStatus;
150
+ };
151
+
152
+ /** Contract principal string in the format `address.contract-name` */
153
+ type TraitReference = `${string}.${string}`;
154
+ /** Union of public function names from a Clarity ABI */
155
+ type PublicFunctionName<TAbi extends ClarityAbi> = ExtractAbiFunctionNames<TAbi, 'public'>;
156
+ /** Named args object for a specific public function, derived from ABI */
157
+ type PublicFunctionArgs<TAbi extends ClarityAbi, TFn extends ExtractAbiFunctionNames<TAbi, 'public'>> = Pretty<{
158
+ [K in ExtractAbiFunction<TAbi, TFn, 'public'>['args'][number] as K['name']]: ClarityAbiArgToPrimitiveTypeValue<K>;
159
+ }>;
160
+
125
161
  interface PostConditionConfig {
126
162
  postConditions: PostCondition[];
127
163
  mode: PostConditionMode;
128
164
  }
129
- interface WriteContractVariables {
165
+ /** Typed mode: ABI present, args is a named object with autocomplete. */
166
+ interface TypedWriteContractVariables<TAbi extends ClarityAbi, TFn extends ExtractAbiFunctionNames<TAbi, 'public'>> {
167
+ abi: TAbi;
168
+ address: string;
169
+ contract: string;
170
+ functionName: TFn;
171
+ args: PublicFunctionArgs<TAbi, TFn>;
172
+ pc: PostConditionConfig;
173
+ }
174
+ /** Untyped mode: no ABI, args is ClarityValue[] (original behavior). */
175
+ interface UntypedWriteContractVariables {
130
176
  address: string;
131
177
  contract: string;
132
178
  functionName: string;
133
179
  args: ClarityValue[];
134
180
  pc: PostConditionConfig;
135
181
  }
182
+ /** Backward-compatible alias for the untyped variant. */
183
+ type WriteContractVariables = UntypedWriteContractVariables;
136
184
  interface WriteContractOptions {
137
185
  onSuccess?: (txHash: string) => void;
138
186
  onError?: (error: Error) => void;
139
187
  onSettled?: (txHash: string | undefined, error: Error | null) => void;
140
188
  }
189
+ /** Overloaded async function: typed mode (with ABI) or untyped mode. */
190
+ interface WriteContractAsyncFn {
191
+ <const TAbi extends ClarityAbi, TFn extends ExtractAbiFunctionNames<TAbi, 'public'>>(variables: TypedWriteContractVariables<TAbi, TFn>): Promise<string>;
192
+ (variables: UntypedWriteContractVariables): Promise<string>;
193
+ }
194
+ /** Overloaded fire-and-forget function: typed mode or untyped mode. */
195
+ interface WriteContractFn {
196
+ <const TAbi extends ClarityAbi, TFn extends ExtractAbiFunctionNames<TAbi, 'public'>>(variables: TypedWriteContractVariables<TAbi, TFn>, options?: WriteContractOptions): void;
197
+ (variables: UntypedWriteContractVariables, options?: WriteContractOptions): void;
198
+ }
141
199
 
142
200
  declare const useWriteContract: () => {
143
- writeContract: (variables: WriteContractVariables, options?: WriteContractOptions) => void;
144
- writeContractAsync: (variables: WriteContractVariables) => Promise<string>;
201
+ writeContract: WriteContractFn;
202
+ writeContractAsync: WriteContractAsyncFn;
145
203
  reset: () => void;
146
204
  data: string | undefined;
147
205
  error: Error | null;
@@ -174,4 +232,15 @@ interface StacksWallets {
174
232
  }
175
233
  declare const getStacksWallets: () => StacksWallets;
176
234
 
177
- export { type ConnectOptions, type MutationStatus, type PostConditionConfig, SUPPORTED_STACKS_WALLETS, type SignMessageData, type SignMessageOptions, type SignMessageVariables, type StacksChain, StacksWalletProvider, type StacksWallets, type SupportedStacksWallet, type WalletConnectMetadata, type WalletContextValue, type WalletInfo, type WalletState, type WriteContractOptions, type WriteContractVariables, getLocalStorageWallet, getNetworkFromAddress, getStacksWallets, useAddress, useBnsName, useConnect, useDisconnect, useSignMessage, useWallets, useWriteContract };
235
+ /** Pre-bind ABI + address + contract for reuse with useWriteContract. */
236
+ declare function createContractConfig<const TAbi extends ClarityAbi>(config: {
237
+ abi: TAbi;
238
+ address: string;
239
+ contract: string;
240
+ }): {
241
+ abi: TAbi;
242
+ address: string;
243
+ contract: string;
244
+ };
245
+
246
+ export { type ConnectOptions, type MutationStatus, type PostConditionConfig, type PublicFunctionArgs, type PublicFunctionName, SUPPORTED_STACKS_WALLETS, type SignMessageData, type SignMessageOptions, type SignMessageVariables, type StacksChain, StacksWalletProvider, type StacksWallets, type SupportedStacksWallet, type TraitReference, type TransferSTXOptions, type TransferSTXVariables, type TypedWriteContractVariables, type UntypedWriteContractVariables, type WalletConnectMetadata, type WalletContextValue, type WalletInfo, type WalletState, type WriteContractOptions, type WriteContractVariables, createContractConfig, getLocalStorageWallet, getNetworkFromAddress, getStacksWallets, useAddress, useBnsName, useConnect, useDisconnect, useSignMessage, useTransferSTX, useWallets, useWriteContract };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { WalletConnect, DEFAULT_PROVIDERS, WALLET_CONNECT_PROVIDER, clearSelectedProviderId, request, getSelectedProviderId, getSelectedProvider, setSelectedProviderId } from '@stacks/connect';
2
2
  import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
- import { PostConditionMode, postConditionToHex, cvToHex } from '@stacks/transactions';
4
+ import { PostConditionMode, postConditionToHex, cvToHex, noneCV, contractPrincipalCV, standardPrincipalCV, boolCV, intCV, uintCV, bufferCV, stringAsciiCV, stringUtf8CV, someCV, listCV, tupleCV } from '@stacks/transactions';
5
5
  import { getPrimaryName } from 'bns-v2-sdk';
6
6
 
7
7
  // src/constants/stacks-provider-mapping.ts
@@ -761,10 +761,239 @@ var getNetworkFromAddress = (address) => {
761
761
  }
762
762
  throw new Error(`Invalid Stacks address: ${address}`);
763
763
  };
764
+
765
+ // src/hooks/use-transfer-stx.ts
766
+ var useTransferSTX = () => {
767
+ const { isConnected, address, provider } = useAddress();
768
+ const [data, setData] = useState(void 0);
769
+ const [error, setError] = useState(null);
770
+ const [status, setStatus] = useState("idle");
771
+ const transferSTXAsync = useCallback(
772
+ async (variables) => {
773
+ if (!isConnected || !address) {
774
+ throw new Error("Wallet is not connected");
775
+ }
776
+ setStatus("pending");
777
+ setError(null);
778
+ setData(void 0);
779
+ try {
780
+ if (provider === "okx") {
781
+ if (!window.okxwallet) {
782
+ throw new Error("OKX wallet not found");
783
+ }
784
+ const response2 = await window.okxwallet.stacks.signTransaction({
785
+ txType: "token_transfer",
786
+ recipient: variables.recipient,
787
+ amount: String(variables.amount),
788
+ memo: variables.memo ?? "",
789
+ stxAddress: address,
790
+ anchorMode: 3
791
+ });
792
+ setData(response2.txHash);
793
+ setStatus("success");
794
+ return response2.txHash;
795
+ }
796
+ const response = await request("stx_transferStx", {
797
+ recipient: variables.recipient,
798
+ amount: variables.amount,
799
+ ...variables.memo !== void 0 && {
800
+ memo: variables.memo
801
+ },
802
+ ...variables.fee !== void 0 && {
803
+ fee: variables.fee
804
+ },
805
+ ...variables.nonce !== void 0 && {
806
+ nonce: variables.nonce
807
+ },
808
+ network: getNetworkFromAddress(address)
809
+ });
810
+ if (!response.txid) {
811
+ throw new Error("No transaction ID returned");
812
+ }
813
+ setData(response.txid);
814
+ setStatus("success");
815
+ return response.txid;
816
+ } catch (err) {
817
+ const error2 = err instanceof Error ? err : new Error(String(err));
818
+ setError(error2);
819
+ setStatus("error");
820
+ throw error2;
821
+ }
822
+ },
823
+ [isConnected, address, provider]
824
+ );
825
+ const transferSTX = useCallback(
826
+ (variables, options) => {
827
+ transferSTXAsync(variables).then((txid) => {
828
+ options?.onSuccess?.(txid);
829
+ options?.onSettled?.(txid, null);
830
+ }).catch((error2) => {
831
+ options?.onError?.(error2);
832
+ options?.onSettled?.(void 0, error2);
833
+ });
834
+ },
835
+ [transferSTXAsync]
836
+ );
837
+ const reset = useCallback(() => {
838
+ setData(void 0);
839
+ setError(null);
840
+ setStatus("idle");
841
+ }, []);
842
+ return useMemo(
843
+ () => ({
844
+ transferSTX,
845
+ transferSTXAsync,
846
+ reset,
847
+ data,
848
+ error,
849
+ isError: status === "error",
850
+ isIdle: status === "idle",
851
+ isPending: status === "pending",
852
+ isSuccess: status === "success",
853
+ status
854
+ }),
855
+ [transferSTX, transferSTXAsync, reset, data, error, status]
856
+ );
857
+ };
858
+ function toClarityValue(value, abiType) {
859
+ if (typeof abiType === "string") {
860
+ switch (abiType) {
861
+ case "uint128": {
862
+ if (typeof value !== "bigint") {
863
+ throw new Error(
864
+ `@satoshai/kit: Expected bigint (uint128), got ${typeof value}`
865
+ );
866
+ }
867
+ return uintCV(value);
868
+ }
869
+ case "int128": {
870
+ if (typeof value !== "bigint") {
871
+ throw new Error(
872
+ `@satoshai/kit: Expected bigint (int128), got ${typeof value}`
873
+ );
874
+ }
875
+ return intCV(value);
876
+ }
877
+ case "bool": {
878
+ if (typeof value !== "boolean") {
879
+ throw new Error(
880
+ `@satoshai/kit: Expected boolean (bool), got ${typeof value}`
881
+ );
882
+ }
883
+ return boolCV(value);
884
+ }
885
+ case "principal":
886
+ case "trait_reference": {
887
+ if (typeof value !== "string") {
888
+ throw new Error(
889
+ `@satoshai/kit: Expected string (${abiType}), got ${typeof value}`
890
+ );
891
+ }
892
+ if (value.includes(".")) {
893
+ const [addr, ...rest] = value.split(".");
894
+ return contractPrincipalCV(addr, rest.join("."));
895
+ }
896
+ return standardPrincipalCV(value);
897
+ }
898
+ case "none":
899
+ return noneCV();
900
+ default:
901
+ throw new Error(
902
+ `@satoshai/kit: Unsupported ABI type "${abiType}"`
903
+ );
904
+ }
905
+ }
906
+ if ("buffer" in abiType) {
907
+ if (!(value instanceof Uint8Array)) {
908
+ throw new Error(
909
+ `@satoshai/kit: Expected Uint8Array (buffer), got ${typeof value}`
910
+ );
911
+ }
912
+ return bufferCV(value);
913
+ }
914
+ if ("string-ascii" in abiType) {
915
+ if (typeof value !== "string") {
916
+ throw new Error(
917
+ `@satoshai/kit: Expected string (string-ascii), got ${typeof value}`
918
+ );
919
+ }
920
+ return stringAsciiCV(value);
921
+ }
922
+ if ("string-utf8" in abiType) {
923
+ if (typeof value !== "string") {
924
+ throw new Error(
925
+ `@satoshai/kit: Expected string (string-utf8), got ${typeof value}`
926
+ );
927
+ }
928
+ return stringUtf8CV(value);
929
+ }
930
+ if ("optional" in abiType) {
931
+ if (value === null || value === void 0) return noneCV();
932
+ return someCV(toClarityValue(value, abiType.optional));
933
+ }
934
+ if ("list" in abiType) {
935
+ if (!Array.isArray(value)) {
936
+ throw new Error(
937
+ `@satoshai/kit: Expected array (list), got ${typeof value}`
938
+ );
939
+ }
940
+ const listType = abiType.list;
941
+ return listCV(
942
+ value.map((item) => toClarityValue(item, listType.type))
943
+ );
944
+ }
945
+ if ("tuple" in abiType) {
946
+ if (typeof value !== "object" || value === null) {
947
+ throw new Error(
948
+ `@satoshai/kit: Expected object (tuple), got ${value === null ? "null" : typeof value}`
949
+ );
950
+ }
951
+ const entries = abiType.tuple;
952
+ const obj = value;
953
+ const result = {};
954
+ for (const entry of entries) {
955
+ result[entry.name] = toClarityValue(obj[entry.name], entry.type);
956
+ }
957
+ return tupleCV(result);
958
+ }
959
+ throw new Error(
960
+ `@satoshai/kit: Unsupported ABI type: ${JSON.stringify(abiType)}`
961
+ );
962
+ }
963
+ function namedArgsToClarityValues(args, abiArgs) {
964
+ return abiArgs.map((abiArg) => {
965
+ if (!(abiArg.name in args)) {
966
+ throw new Error(
967
+ `@satoshai/kit: Missing argument "${abiArg.name}"`
968
+ );
969
+ }
970
+ return toClarityValue(
971
+ args[abiArg.name],
972
+ abiArg.type
973
+ );
974
+ });
975
+ }
764
976
  var preparePostConditionsForOKX = (postConditions) => postConditions.map((pc) => postConditionToHex(pc));
765
977
  var prepareArgsForOKX = (args) => args.map((arg) => cvToHex(arg));
766
978
 
767
979
  // src/hooks/use-write-contract/use-write-contract.ts
980
+ function resolveArgs(variables) {
981
+ if (!variables.abi) {
982
+ return variables.args;
983
+ }
984
+ const fn = variables.abi.functions.find(
985
+ (f) => f.name === variables.functionName && f.access === "public"
986
+ );
987
+ if (!fn) {
988
+ throw new Error(
989
+ `@satoshai/kit: Public function "${variables.functionName}" not found in ABI`
990
+ );
991
+ }
992
+ return namedArgsToClarityValues(
993
+ variables.args,
994
+ fn.args
995
+ );
996
+ }
768
997
  var useWriteContract = () => {
769
998
  const { isConnected, address, provider } = useAddress();
770
999
  const [data, setData] = useState(void 0);
@@ -778,6 +1007,7 @@ var useWriteContract = () => {
778
1007
  setStatus("pending");
779
1008
  setError(null);
780
1009
  setData(void 0);
1010
+ const resolvedArgs = resolveArgs(variables);
781
1011
  try {
782
1012
  if (provider === "okx") {
783
1013
  if (!window.okxwallet) {
@@ -787,7 +1017,7 @@ var useWriteContract = () => {
787
1017
  contractAddress: variables.address,
788
1018
  contractName: variables.contract,
789
1019
  functionName: variables.functionName,
790
- functionArgs: prepareArgsForOKX(variables.args),
1020
+ functionArgs: prepareArgsForOKX(resolvedArgs),
791
1021
  postConditions: preparePostConditionsForOKX(
792
1022
  variables.pc.postConditions
793
1023
  ),
@@ -804,7 +1034,7 @@ var useWriteContract = () => {
804
1034
  address,
805
1035
  contract: `${variables.address}.${variables.contract}`,
806
1036
  functionName: variables.functionName,
807
- functionArgs: variables.args,
1037
+ functionArgs: resolvedArgs,
808
1038
  postConditions: variables.pc.postConditions,
809
1039
  postConditionMode: variables.pc.mode === PostConditionMode.Allow ? "allow" : "deny",
810
1040
  network: getNetworkFromAddress(address)
@@ -896,6 +1126,11 @@ var useWallets = () => {
896
1126
  return useMemo(() => ({ wallets }), [wallets]);
897
1127
  };
898
1128
 
899
- export { SUPPORTED_STACKS_WALLETS, StacksWalletProvider, getLocalStorageWallet, getNetworkFromAddress, getStacksWallets, useAddress, useBnsName, useConnect, useDisconnect, useSignMessage, useWallets, useWriteContract };
1129
+ // src/utils/create-contract-config.ts
1130
+ function createContractConfig(config) {
1131
+ return config;
1132
+ }
1133
+
1134
+ export { SUPPORTED_STACKS_WALLETS, StacksWalletProvider, createContractConfig, getLocalStorageWallet, getNetworkFromAddress, getStacksWallets, useAddress, useBnsName, useConnect, useDisconnect, useSignMessage, useTransferSTX, useWallets, useWriteContract };
900
1135
  //# sourceMappingURL=index.js.map
901
1136
  //# sourceMappingURL=index.js.map