@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/README.md +23 -0
- package/dist/index.cjs +239 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -4
- package/dist/index.d.ts +73 -4
- package/dist/index.js +239 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Typesafe Stacks wallet & contract interaction library for React. Wagmi-inspired
|
|
|
10
10
|
- **`useAddress`** — Access connected wallet address and status
|
|
11
11
|
- **`useSignMessage`** — Sign arbitrary messages
|
|
12
12
|
- **`useWriteContract`** — Call smart contracts with post-conditions
|
|
13
|
+
- **`useTransferSTX`** — Native STX transfers
|
|
13
14
|
- **`useBnsName`** — Resolve BNS v2 names
|
|
14
15
|
- **6 wallets supported** — Xverse, Leather, OKX, Asigna, Fordefi, WalletConnect
|
|
15
16
|
- **Next.js App Router compatible** — `"use client"` directives included
|
|
@@ -179,6 +180,28 @@ signMessage({ message: 'Hello Stacks' }, {
|
|
|
179
180
|
const { publicKey, signature } = await signMessageAsync({ message: 'Hello Stacks' });
|
|
180
181
|
```
|
|
181
182
|
|
|
183
|
+
### `useTransferSTX()`
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const { transferSTX, transferSTXAsync, data, error, isPending } = useTransferSTX();
|
|
187
|
+
|
|
188
|
+
// Callback style
|
|
189
|
+
transferSTX({
|
|
190
|
+
recipient: 'SP2...',
|
|
191
|
+
amount: 1000000n, // in microSTX
|
|
192
|
+
memo: 'optional memo',
|
|
193
|
+
}, {
|
|
194
|
+
onSuccess: (txid) => {},
|
|
195
|
+
onError: (error) => {},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Async style
|
|
199
|
+
const txid = await transferSTXAsync({
|
|
200
|
+
recipient: 'SP2...',
|
|
201
|
+
amount: 1000000n,
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
182
205
|
### `useWriteContract()`
|
|
183
206
|
|
|
184
207
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -763,10 +763,239 @@ var getNetworkFromAddress = (address) => {
|
|
|
763
763
|
}
|
|
764
764
|
throw new Error(`Invalid Stacks address: ${address}`);
|
|
765
765
|
};
|
|
766
|
+
|
|
767
|
+
// src/hooks/use-transfer-stx.ts
|
|
768
|
+
var useTransferSTX = () => {
|
|
769
|
+
const { isConnected, address, provider } = useAddress();
|
|
770
|
+
const [data, setData] = react.useState(void 0);
|
|
771
|
+
const [error, setError] = react.useState(null);
|
|
772
|
+
const [status, setStatus] = react.useState("idle");
|
|
773
|
+
const transferSTXAsync = react.useCallback(
|
|
774
|
+
async (variables) => {
|
|
775
|
+
if (!isConnected || !address) {
|
|
776
|
+
throw new Error("Wallet is not connected");
|
|
777
|
+
}
|
|
778
|
+
setStatus("pending");
|
|
779
|
+
setError(null);
|
|
780
|
+
setData(void 0);
|
|
781
|
+
try {
|
|
782
|
+
if (provider === "okx") {
|
|
783
|
+
if (!window.okxwallet) {
|
|
784
|
+
throw new Error("OKX wallet not found");
|
|
785
|
+
}
|
|
786
|
+
const response2 = await window.okxwallet.stacks.signTransaction({
|
|
787
|
+
txType: "token_transfer",
|
|
788
|
+
recipient: variables.recipient,
|
|
789
|
+
amount: String(variables.amount),
|
|
790
|
+
memo: variables.memo ?? "",
|
|
791
|
+
stxAddress: address,
|
|
792
|
+
anchorMode: 3
|
|
793
|
+
});
|
|
794
|
+
setData(response2.txHash);
|
|
795
|
+
setStatus("success");
|
|
796
|
+
return response2.txHash;
|
|
797
|
+
}
|
|
798
|
+
const response = await connect.request("stx_transferStx", {
|
|
799
|
+
recipient: variables.recipient,
|
|
800
|
+
amount: variables.amount,
|
|
801
|
+
...variables.memo !== void 0 && {
|
|
802
|
+
memo: variables.memo
|
|
803
|
+
},
|
|
804
|
+
...variables.fee !== void 0 && {
|
|
805
|
+
fee: variables.fee
|
|
806
|
+
},
|
|
807
|
+
...variables.nonce !== void 0 && {
|
|
808
|
+
nonce: variables.nonce
|
|
809
|
+
},
|
|
810
|
+
network: getNetworkFromAddress(address)
|
|
811
|
+
});
|
|
812
|
+
if (!response.txid) {
|
|
813
|
+
throw new Error("No transaction ID returned");
|
|
814
|
+
}
|
|
815
|
+
setData(response.txid);
|
|
816
|
+
setStatus("success");
|
|
817
|
+
return response.txid;
|
|
818
|
+
} catch (err) {
|
|
819
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
820
|
+
setError(error2);
|
|
821
|
+
setStatus("error");
|
|
822
|
+
throw error2;
|
|
823
|
+
}
|
|
824
|
+
},
|
|
825
|
+
[isConnected, address, provider]
|
|
826
|
+
);
|
|
827
|
+
const transferSTX = react.useCallback(
|
|
828
|
+
(variables, options) => {
|
|
829
|
+
transferSTXAsync(variables).then((txid) => {
|
|
830
|
+
options?.onSuccess?.(txid);
|
|
831
|
+
options?.onSettled?.(txid, null);
|
|
832
|
+
}).catch((error2) => {
|
|
833
|
+
options?.onError?.(error2);
|
|
834
|
+
options?.onSettled?.(void 0, error2);
|
|
835
|
+
});
|
|
836
|
+
},
|
|
837
|
+
[transferSTXAsync]
|
|
838
|
+
);
|
|
839
|
+
const reset = react.useCallback(() => {
|
|
840
|
+
setData(void 0);
|
|
841
|
+
setError(null);
|
|
842
|
+
setStatus("idle");
|
|
843
|
+
}, []);
|
|
844
|
+
return react.useMemo(
|
|
845
|
+
() => ({
|
|
846
|
+
transferSTX,
|
|
847
|
+
transferSTXAsync,
|
|
848
|
+
reset,
|
|
849
|
+
data,
|
|
850
|
+
error,
|
|
851
|
+
isError: status === "error",
|
|
852
|
+
isIdle: status === "idle",
|
|
853
|
+
isPending: status === "pending",
|
|
854
|
+
isSuccess: status === "success",
|
|
855
|
+
status
|
|
856
|
+
}),
|
|
857
|
+
[transferSTX, transferSTXAsync, reset, data, error, status]
|
|
858
|
+
);
|
|
859
|
+
};
|
|
860
|
+
function toClarityValue(value, abiType) {
|
|
861
|
+
if (typeof abiType === "string") {
|
|
862
|
+
switch (abiType) {
|
|
863
|
+
case "uint128": {
|
|
864
|
+
if (typeof value !== "bigint") {
|
|
865
|
+
throw new Error(
|
|
866
|
+
`@satoshai/kit: Expected bigint (uint128), got ${typeof value}`
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
return transactions.uintCV(value);
|
|
870
|
+
}
|
|
871
|
+
case "int128": {
|
|
872
|
+
if (typeof value !== "bigint") {
|
|
873
|
+
throw new Error(
|
|
874
|
+
`@satoshai/kit: Expected bigint (int128), got ${typeof value}`
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
return transactions.intCV(value);
|
|
878
|
+
}
|
|
879
|
+
case "bool": {
|
|
880
|
+
if (typeof value !== "boolean") {
|
|
881
|
+
throw new Error(
|
|
882
|
+
`@satoshai/kit: Expected boolean (bool), got ${typeof value}`
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
return transactions.boolCV(value);
|
|
886
|
+
}
|
|
887
|
+
case "principal":
|
|
888
|
+
case "trait_reference": {
|
|
889
|
+
if (typeof value !== "string") {
|
|
890
|
+
throw new Error(
|
|
891
|
+
`@satoshai/kit: Expected string (${abiType}), got ${typeof value}`
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
if (value.includes(".")) {
|
|
895
|
+
const [addr, ...rest] = value.split(".");
|
|
896
|
+
return transactions.contractPrincipalCV(addr, rest.join("."));
|
|
897
|
+
}
|
|
898
|
+
return transactions.standardPrincipalCV(value);
|
|
899
|
+
}
|
|
900
|
+
case "none":
|
|
901
|
+
return transactions.noneCV();
|
|
902
|
+
default:
|
|
903
|
+
throw new Error(
|
|
904
|
+
`@satoshai/kit: Unsupported ABI type "${abiType}"`
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
if ("buffer" in abiType) {
|
|
909
|
+
if (!(value instanceof Uint8Array)) {
|
|
910
|
+
throw new Error(
|
|
911
|
+
`@satoshai/kit: Expected Uint8Array (buffer), got ${typeof value}`
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
return transactions.bufferCV(value);
|
|
915
|
+
}
|
|
916
|
+
if ("string-ascii" in abiType) {
|
|
917
|
+
if (typeof value !== "string") {
|
|
918
|
+
throw new Error(
|
|
919
|
+
`@satoshai/kit: Expected string (string-ascii), got ${typeof value}`
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
return transactions.stringAsciiCV(value);
|
|
923
|
+
}
|
|
924
|
+
if ("string-utf8" in abiType) {
|
|
925
|
+
if (typeof value !== "string") {
|
|
926
|
+
throw new Error(
|
|
927
|
+
`@satoshai/kit: Expected string (string-utf8), got ${typeof value}`
|
|
928
|
+
);
|
|
929
|
+
}
|
|
930
|
+
return transactions.stringUtf8CV(value);
|
|
931
|
+
}
|
|
932
|
+
if ("optional" in abiType) {
|
|
933
|
+
if (value === null || value === void 0) return transactions.noneCV();
|
|
934
|
+
return transactions.someCV(toClarityValue(value, abiType.optional));
|
|
935
|
+
}
|
|
936
|
+
if ("list" in abiType) {
|
|
937
|
+
if (!Array.isArray(value)) {
|
|
938
|
+
throw new Error(
|
|
939
|
+
`@satoshai/kit: Expected array (list), got ${typeof value}`
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
const listType = abiType.list;
|
|
943
|
+
return transactions.listCV(
|
|
944
|
+
value.map((item) => toClarityValue(item, listType.type))
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
if ("tuple" in abiType) {
|
|
948
|
+
if (typeof value !== "object" || value === null) {
|
|
949
|
+
throw new Error(
|
|
950
|
+
`@satoshai/kit: Expected object (tuple), got ${value === null ? "null" : typeof value}`
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
const entries = abiType.tuple;
|
|
954
|
+
const obj = value;
|
|
955
|
+
const result = {};
|
|
956
|
+
for (const entry of entries) {
|
|
957
|
+
result[entry.name] = toClarityValue(obj[entry.name], entry.type);
|
|
958
|
+
}
|
|
959
|
+
return transactions.tupleCV(result);
|
|
960
|
+
}
|
|
961
|
+
throw new Error(
|
|
962
|
+
`@satoshai/kit: Unsupported ABI type: ${JSON.stringify(abiType)}`
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
function namedArgsToClarityValues(args, abiArgs) {
|
|
966
|
+
return abiArgs.map((abiArg) => {
|
|
967
|
+
if (!(abiArg.name in args)) {
|
|
968
|
+
throw new Error(
|
|
969
|
+
`@satoshai/kit: Missing argument "${abiArg.name}"`
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
return toClarityValue(
|
|
973
|
+
args[abiArg.name],
|
|
974
|
+
abiArg.type
|
|
975
|
+
);
|
|
976
|
+
});
|
|
977
|
+
}
|
|
766
978
|
var preparePostConditionsForOKX = (postConditions) => postConditions.map((pc) => transactions.postConditionToHex(pc));
|
|
767
979
|
var prepareArgsForOKX = (args) => args.map((arg) => transactions.cvToHex(arg));
|
|
768
980
|
|
|
769
981
|
// src/hooks/use-write-contract/use-write-contract.ts
|
|
982
|
+
function resolveArgs(variables) {
|
|
983
|
+
if (!variables.abi) {
|
|
984
|
+
return variables.args;
|
|
985
|
+
}
|
|
986
|
+
const fn = variables.abi.functions.find(
|
|
987
|
+
(f) => f.name === variables.functionName && f.access === "public"
|
|
988
|
+
);
|
|
989
|
+
if (!fn) {
|
|
990
|
+
throw new Error(
|
|
991
|
+
`@satoshai/kit: Public function "${variables.functionName}" not found in ABI`
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
return namedArgsToClarityValues(
|
|
995
|
+
variables.args,
|
|
996
|
+
fn.args
|
|
997
|
+
);
|
|
998
|
+
}
|
|
770
999
|
var useWriteContract = () => {
|
|
771
1000
|
const { isConnected, address, provider } = useAddress();
|
|
772
1001
|
const [data, setData] = react.useState(void 0);
|
|
@@ -780,6 +1009,7 @@ var useWriteContract = () => {
|
|
|
780
1009
|
setStatus("pending");
|
|
781
1010
|
setError(null);
|
|
782
1011
|
setData(void 0);
|
|
1012
|
+
const resolvedArgs = resolveArgs(variables);
|
|
783
1013
|
try {
|
|
784
1014
|
if (provider === "okx") {
|
|
785
1015
|
if (!window.okxwallet) {
|
|
@@ -789,7 +1019,7 @@ var useWriteContract = () => {
|
|
|
789
1019
|
contractAddress: variables.address,
|
|
790
1020
|
contractName: variables.contract,
|
|
791
1021
|
functionName: variables.functionName,
|
|
792
|
-
functionArgs: prepareArgsForOKX(
|
|
1022
|
+
functionArgs: prepareArgsForOKX(resolvedArgs),
|
|
793
1023
|
postConditions: preparePostConditionsForOKX(
|
|
794
1024
|
variables.pc.postConditions
|
|
795
1025
|
),
|
|
@@ -806,7 +1036,7 @@ var useWriteContract = () => {
|
|
|
806
1036
|
address,
|
|
807
1037
|
contract: `${variables.address}.${variables.contract}`,
|
|
808
1038
|
functionName: variables.functionName,
|
|
809
|
-
functionArgs:
|
|
1039
|
+
functionArgs: resolvedArgs,
|
|
810
1040
|
postConditions: variables.pc.postConditions,
|
|
811
1041
|
postConditionMode: variables.pc.mode === transactions.PostConditionMode.Allow ? "allow" : "deny",
|
|
812
1042
|
network: getNetworkFromAddress(address)
|
|
@@ -898,8 +1128,14 @@ var useWallets = () => {
|
|
|
898
1128
|
return react.useMemo(() => ({ wallets }), [wallets]);
|
|
899
1129
|
};
|
|
900
1130
|
|
|
1131
|
+
// src/utils/create-contract-config.ts
|
|
1132
|
+
function createContractConfig(config) {
|
|
1133
|
+
return config;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
901
1136
|
exports.SUPPORTED_STACKS_WALLETS = SUPPORTED_STACKS_WALLETS;
|
|
902
1137
|
exports.StacksWalletProvider = StacksWalletProvider;
|
|
1138
|
+
exports.createContractConfig = createContractConfig;
|
|
903
1139
|
exports.getLocalStorageWallet = getLocalStorageWallet;
|
|
904
1140
|
exports.getNetworkFromAddress = getNetworkFromAddress;
|
|
905
1141
|
exports.getStacksWallets = getStacksWallets;
|
|
@@ -908,6 +1144,7 @@ exports.useBnsName = useBnsName;
|
|
|
908
1144
|
exports.useConnect = useConnect;
|
|
909
1145
|
exports.useDisconnect = useDisconnect;
|
|
910
1146
|
exports.useSignMessage = useSignMessage;
|
|
1147
|
+
exports.useTransferSTX = useTransferSTX;
|
|
911
1148
|
exports.useWallets = useWallets;
|
|
912
1149
|
exports.useWriteContract = useWriteContract;
|
|
913
1150
|
//# sourceMappingURL=index.cjs.map
|