anymal-protocol 1.0.2 → 1.0.4
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.mts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +191 -2
- package/dist/index.mjs +188 -2
- package/package.json +1 -1
- package/src/helpers/UploadImageHelper.tsx +63 -0
- package/src/index.ts +4 -1
- package/src/utils/{useVerifyAccount.ts → account/useVerifyAccount.ts} +1 -1
- package/src/utils/anymals/useUploadAnymalImage.ts +70 -0
- package/src/utils/balance/useFetchBalance.ts +26 -0
package/dist/index.d.mts
CHANGED
|
@@ -30,4 +30,17 @@ declare function useSaveAnymalMetadata(): (idToken: string, publicKey: string, n
|
|
|
30
30
|
message: any;
|
|
31
31
|
}>;
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
declare function useUpdateAnymalWithNFT(): (anymalPassportId: string, anymalDocId: string, dbAuthToken: string, endpoint: string) => Promise<{
|
|
34
|
+
success: boolean;
|
|
35
|
+
}>;
|
|
36
|
+
|
|
37
|
+
declare function useFetchBalance(): (publicClient: any, walletAddress: string, kibbleTokenAddress: string) => Promise<number | undefined>;
|
|
38
|
+
|
|
39
|
+
declare function useUploadAnymalImage(): (imageFile: File, type: string, idToken: string, publicKey: string, authServiceBaseUrl: string) => Promise<{
|
|
40
|
+
success: boolean;
|
|
41
|
+
message: string;
|
|
42
|
+
url: any;
|
|
43
|
+
type: string;
|
|
44
|
+
}>;
|
|
45
|
+
|
|
46
|
+
export { type AnymalNftMetadataInputData, type CreateAnymalInputData, useAddAnymalToDatabase, useDeleteAnymalFromDatabase, useFetchBalance, useMintAnymalNFT, useSaveAnymalMetadata, useUpdateAnymalWithNFT, useUploadAnymalImage, useVerifyAccount };
|
package/dist/index.d.ts
CHANGED
|
@@ -30,4 +30,17 @@ declare function useSaveAnymalMetadata(): (idToken: string, publicKey: string, n
|
|
|
30
30
|
message: any;
|
|
31
31
|
}>;
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
declare function useUpdateAnymalWithNFT(): (anymalPassportId: string, anymalDocId: string, dbAuthToken: string, endpoint: string) => Promise<{
|
|
34
|
+
success: boolean;
|
|
35
|
+
}>;
|
|
36
|
+
|
|
37
|
+
declare function useFetchBalance(): (publicClient: any, walletAddress: string, kibbleTokenAddress: string) => Promise<number | undefined>;
|
|
38
|
+
|
|
39
|
+
declare function useUploadAnymalImage(): (imageFile: File, type: string, idToken: string, publicKey: string, authServiceBaseUrl: string) => Promise<{
|
|
40
|
+
success: boolean;
|
|
41
|
+
message: string;
|
|
42
|
+
url: any;
|
|
43
|
+
type: string;
|
|
44
|
+
}>;
|
|
45
|
+
|
|
46
|
+
export { type AnymalNftMetadataInputData, type CreateAnymalInputData, useAddAnymalToDatabase, useDeleteAnymalFromDatabase, useFetchBalance, useMintAnymalNFT, useSaveAnymalMetadata, useUpdateAnymalWithNFT, useUploadAnymalImage, useVerifyAccount };
|
package/dist/index.js
CHANGED
|
@@ -22,13 +22,16 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
useAddAnymalToDatabase: () => useAddAnymalToDatabase,
|
|
24
24
|
useDeleteAnymalFromDatabase: () => useDeleteAnymalFromDatabase,
|
|
25
|
+
useFetchBalance: () => useFetchBalance,
|
|
25
26
|
useMintAnymalNFT: () => useMintAnymalNFT,
|
|
26
27
|
useSaveAnymalMetadata: () => useSaveAnymalMetadata,
|
|
28
|
+
useUpdateAnymalWithNFT: () => useUpdateAnymalWithNFT,
|
|
29
|
+
useUploadAnymalImage: () => useUploadAnymalImage,
|
|
27
30
|
useVerifyAccount: () => useVerifyAccount
|
|
28
31
|
});
|
|
29
32
|
module.exports = __toCommonJS(index_exports);
|
|
30
33
|
|
|
31
|
-
// src/utils/useVerifyAccount.ts
|
|
34
|
+
// src/utils/account/useVerifyAccount.ts
|
|
32
35
|
var import_react = require("react");
|
|
33
36
|
var import_viem = require("viem");
|
|
34
37
|
|
|
@@ -589,7 +592,7 @@ var VERIFY_ACCOUNT_ABI = [
|
|
|
589
592
|
}
|
|
590
593
|
];
|
|
591
594
|
|
|
592
|
-
// src/utils/useVerifyAccount.ts
|
|
595
|
+
// src/utils/account/useVerifyAccount.ts
|
|
593
596
|
function useVerifyAccount() {
|
|
594
597
|
return (0, import_react.useCallback)(
|
|
595
598
|
async (pid, dbAuthToken, bundlerClient, smartAccount, accountRewardsContractAddress) => {
|
|
@@ -806,11 +809,197 @@ function useSaveAnymalMetadata() {
|
|
|
806
809
|
[]
|
|
807
810
|
);
|
|
808
811
|
}
|
|
812
|
+
|
|
813
|
+
// src/utils/anymals/useUpdateAnymalWithNFT.ts
|
|
814
|
+
var import_react6 = require("react");
|
|
815
|
+
function useUpdateAnymalWithNFT() {
|
|
816
|
+
return (0, import_react6.useCallback)(
|
|
817
|
+
async (anymalPassportId, anymalDocId, dbAuthToken, endpoint) => {
|
|
818
|
+
if (!dbAuthToken || !anymalPassportId || !anymalDocId || !endpoint) {
|
|
819
|
+
return {
|
|
820
|
+
success: false
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
try {
|
|
824
|
+
const mutation = `
|
|
825
|
+
mutation {
|
|
826
|
+
update_Anymal(
|
|
827
|
+
docID: [${JSON.stringify(anymalDocId)}],
|
|
828
|
+
input: {
|
|
829
|
+
passportID: "${anymalPassportId}"
|
|
830
|
+
}
|
|
831
|
+
) {
|
|
832
|
+
passportID
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
`;
|
|
836
|
+
const response = await fetch(endpoint, {
|
|
837
|
+
method: "POST",
|
|
838
|
+
headers: {
|
|
839
|
+
"Content-Type": "application/json",
|
|
840
|
+
Authorization: `Bearer ${dbAuthToken}`
|
|
841
|
+
},
|
|
842
|
+
body: JSON.stringify({ query: mutation })
|
|
843
|
+
});
|
|
844
|
+
if (!response.ok) {
|
|
845
|
+
return { success: false };
|
|
846
|
+
}
|
|
847
|
+
const { errors } = await response.json();
|
|
848
|
+
if (errors) {
|
|
849
|
+
console.log(`GQL error: ${JSON.stringify(errors)}`);
|
|
850
|
+
return { success: false };
|
|
851
|
+
}
|
|
852
|
+
return { success: true };
|
|
853
|
+
} catch (error) {
|
|
854
|
+
console.error("Error updating Anymal with NFT ID:", error);
|
|
855
|
+
return { success: false };
|
|
856
|
+
}
|
|
857
|
+
},
|
|
858
|
+
[]
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
// src/utils/balance/useFetchBalance.ts
|
|
863
|
+
var import_react7 = require("react");
|
|
864
|
+
var import_viem3 = require("viem");
|
|
865
|
+
function useFetchBalance() {
|
|
866
|
+
return (0, import_react7.useCallback)(
|
|
867
|
+
async (publicClient, walletAddress, kibbleTokenAddress) => {
|
|
868
|
+
try {
|
|
869
|
+
const balance = await publicClient.readContract({
|
|
870
|
+
address: (0, import_viem3.getAddress)(kibbleTokenAddress),
|
|
871
|
+
abi: import_viem3.erc20Abi,
|
|
872
|
+
functionName: "balanceOf",
|
|
873
|
+
args: [(0, import_viem3.getAddress)(walletAddress)]
|
|
874
|
+
});
|
|
875
|
+
return Number(balance);
|
|
876
|
+
} catch (error) {
|
|
877
|
+
console.error("Failed to fetch token balance:", error);
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
[]
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// src/utils/anymals/useUploadAnymalImage.ts
|
|
885
|
+
var import_react8 = require("react");
|
|
886
|
+
|
|
887
|
+
// src/helpers/UploadImageHelper.tsx
|
|
888
|
+
function resizeImage(file, maxWidth = 800, maxHeight = 800, quality = 0.7) {
|
|
889
|
+
return new Promise((resolve, reject) => {
|
|
890
|
+
const img = new Image();
|
|
891
|
+
img.src = URL.createObjectURL(file);
|
|
892
|
+
img.onload = () => {
|
|
893
|
+
const canvas = document.createElement("canvas");
|
|
894
|
+
const ctx = canvas.getContext("2d");
|
|
895
|
+
if (!ctx) {
|
|
896
|
+
reject(new Error("Failed to get canvas 2D context"));
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
let width = img.width;
|
|
900
|
+
let height = img.height;
|
|
901
|
+
if (width > height) {
|
|
902
|
+
if (width > maxWidth) {
|
|
903
|
+
height = Math.round(height *= maxWidth / width);
|
|
904
|
+
width = maxWidth;
|
|
905
|
+
}
|
|
906
|
+
} else {
|
|
907
|
+
if (height > maxHeight) {
|
|
908
|
+
width = Math.round(width *= maxHeight / height);
|
|
909
|
+
height = maxHeight;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
canvas.width = width;
|
|
913
|
+
canvas.height = height;
|
|
914
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
915
|
+
canvas.toBlob(
|
|
916
|
+
(blob) => {
|
|
917
|
+
if (blob) resolve(blob);
|
|
918
|
+
else reject(new Error("Image compression failed."));
|
|
919
|
+
},
|
|
920
|
+
"image/jpeg",
|
|
921
|
+
quality
|
|
922
|
+
);
|
|
923
|
+
};
|
|
924
|
+
img.onerror = () => reject(new Error("Failed to load image."));
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
async function prepareImage(imageFile) {
|
|
928
|
+
const compressedFile = await resizeImage(imageFile);
|
|
929
|
+
return toBase64(compressedFile);
|
|
930
|
+
}
|
|
931
|
+
function toBase64(file) {
|
|
932
|
+
return new Promise((resolve, reject) => {
|
|
933
|
+
const reader = new FileReader();
|
|
934
|
+
reader.readAsDataURL(file);
|
|
935
|
+
reader.onload = () => resolve(reader.result.split(",")[1]);
|
|
936
|
+
reader.onerror = (error) => reject(error);
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// src/utils/anymals/useUploadAnymalImage.ts
|
|
941
|
+
function useUploadAnymalImage() {
|
|
942
|
+
return (0, import_react8.useCallback)(
|
|
943
|
+
async (imageFile, type, idToken, publicKey, authServiceBaseUrl) => {
|
|
944
|
+
if (!imageFile || !idToken) {
|
|
945
|
+
return {
|
|
946
|
+
success: false,
|
|
947
|
+
message: "No image file selected or not authenticated.",
|
|
948
|
+
url: null,
|
|
949
|
+
type
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
try {
|
|
953
|
+
const base64Image = await prepareImage(imageFile);
|
|
954
|
+
const payload = {
|
|
955
|
+
appPubKey: publicKey,
|
|
956
|
+
imageData: base64Image,
|
|
957
|
+
imageName: imageFile.name.split(".")[0]
|
|
958
|
+
};
|
|
959
|
+
const response = await fetch(`${authServiceBaseUrl}/process-image`, {
|
|
960
|
+
method: "POST",
|
|
961
|
+
headers: {
|
|
962
|
+
"Content-Type": "application/json",
|
|
963
|
+
Authorization: `Bearer ${idToken}`
|
|
964
|
+
},
|
|
965
|
+
body: JSON.stringify(payload)
|
|
966
|
+
});
|
|
967
|
+
const data = await response.json();
|
|
968
|
+
if (response.ok) {
|
|
969
|
+
return {
|
|
970
|
+
success: true,
|
|
971
|
+
message: "Image uploaded successfully.",
|
|
972
|
+
url: data.ipfsUrl,
|
|
973
|
+
type
|
|
974
|
+
};
|
|
975
|
+
} else {
|
|
976
|
+
return {
|
|
977
|
+
success: false,
|
|
978
|
+
message: "Image failed to upload.",
|
|
979
|
+
url: null,
|
|
980
|
+
type
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
} catch (error) {
|
|
984
|
+
return {
|
|
985
|
+
success: false,
|
|
986
|
+
message: `An error occurred during image upload: ${error.message}`,
|
|
987
|
+
url: null,
|
|
988
|
+
type
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
[]
|
|
993
|
+
);
|
|
994
|
+
}
|
|
809
995
|
// Annotate the CommonJS export names for ESM import in node:
|
|
810
996
|
0 && (module.exports = {
|
|
811
997
|
useAddAnymalToDatabase,
|
|
812
998
|
useDeleteAnymalFromDatabase,
|
|
999
|
+
useFetchBalance,
|
|
813
1000
|
useMintAnymalNFT,
|
|
814
1001
|
useSaveAnymalMetadata,
|
|
1002
|
+
useUpdateAnymalWithNFT,
|
|
1003
|
+
useUploadAnymalImage,
|
|
815
1004
|
useVerifyAccount
|
|
816
1005
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/utils/useVerifyAccount.ts
|
|
1
|
+
// src/utils/account/useVerifyAccount.ts
|
|
2
2
|
import { useCallback } from "react";
|
|
3
3
|
import { encodeFunctionData, parseGwei } from "viem";
|
|
4
4
|
|
|
@@ -559,7 +559,7 @@ var VERIFY_ACCOUNT_ABI = [
|
|
|
559
559
|
}
|
|
560
560
|
];
|
|
561
561
|
|
|
562
|
-
// src/utils/useVerifyAccount.ts
|
|
562
|
+
// src/utils/account/useVerifyAccount.ts
|
|
563
563
|
function useVerifyAccount() {
|
|
564
564
|
return useCallback(
|
|
565
565
|
async (pid, dbAuthToken, bundlerClient, smartAccount, accountRewardsContractAddress) => {
|
|
@@ -776,10 +776,196 @@ function useSaveAnymalMetadata() {
|
|
|
776
776
|
[]
|
|
777
777
|
);
|
|
778
778
|
}
|
|
779
|
+
|
|
780
|
+
// src/utils/anymals/useUpdateAnymalWithNFT.ts
|
|
781
|
+
import { useCallback as useCallback6 } from "react";
|
|
782
|
+
function useUpdateAnymalWithNFT() {
|
|
783
|
+
return useCallback6(
|
|
784
|
+
async (anymalPassportId, anymalDocId, dbAuthToken, endpoint) => {
|
|
785
|
+
if (!dbAuthToken || !anymalPassportId || !anymalDocId || !endpoint) {
|
|
786
|
+
return {
|
|
787
|
+
success: false
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
try {
|
|
791
|
+
const mutation = `
|
|
792
|
+
mutation {
|
|
793
|
+
update_Anymal(
|
|
794
|
+
docID: [${JSON.stringify(anymalDocId)}],
|
|
795
|
+
input: {
|
|
796
|
+
passportID: "${anymalPassportId}"
|
|
797
|
+
}
|
|
798
|
+
) {
|
|
799
|
+
passportID
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
`;
|
|
803
|
+
const response = await fetch(endpoint, {
|
|
804
|
+
method: "POST",
|
|
805
|
+
headers: {
|
|
806
|
+
"Content-Type": "application/json",
|
|
807
|
+
Authorization: `Bearer ${dbAuthToken}`
|
|
808
|
+
},
|
|
809
|
+
body: JSON.stringify({ query: mutation })
|
|
810
|
+
});
|
|
811
|
+
if (!response.ok) {
|
|
812
|
+
return { success: false };
|
|
813
|
+
}
|
|
814
|
+
const { errors } = await response.json();
|
|
815
|
+
if (errors) {
|
|
816
|
+
console.log(`GQL error: ${JSON.stringify(errors)}`);
|
|
817
|
+
return { success: false };
|
|
818
|
+
}
|
|
819
|
+
return { success: true };
|
|
820
|
+
} catch (error) {
|
|
821
|
+
console.error("Error updating Anymal with NFT ID:", error);
|
|
822
|
+
return { success: false };
|
|
823
|
+
}
|
|
824
|
+
},
|
|
825
|
+
[]
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// src/utils/balance/useFetchBalance.ts
|
|
830
|
+
import { useCallback as useCallback7 } from "react";
|
|
831
|
+
import { erc20Abi, getAddress } from "viem";
|
|
832
|
+
function useFetchBalance() {
|
|
833
|
+
return useCallback7(
|
|
834
|
+
async (publicClient, walletAddress, kibbleTokenAddress) => {
|
|
835
|
+
try {
|
|
836
|
+
const balance = await publicClient.readContract({
|
|
837
|
+
address: getAddress(kibbleTokenAddress),
|
|
838
|
+
abi: erc20Abi,
|
|
839
|
+
functionName: "balanceOf",
|
|
840
|
+
args: [getAddress(walletAddress)]
|
|
841
|
+
});
|
|
842
|
+
return Number(balance);
|
|
843
|
+
} catch (error) {
|
|
844
|
+
console.error("Failed to fetch token balance:", error);
|
|
845
|
+
}
|
|
846
|
+
},
|
|
847
|
+
[]
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// src/utils/anymals/useUploadAnymalImage.ts
|
|
852
|
+
import { useCallback as useCallback8 } from "react";
|
|
853
|
+
|
|
854
|
+
// src/helpers/UploadImageHelper.tsx
|
|
855
|
+
function resizeImage(file, maxWidth = 800, maxHeight = 800, quality = 0.7) {
|
|
856
|
+
return new Promise((resolve, reject) => {
|
|
857
|
+
const img = new Image();
|
|
858
|
+
img.src = URL.createObjectURL(file);
|
|
859
|
+
img.onload = () => {
|
|
860
|
+
const canvas = document.createElement("canvas");
|
|
861
|
+
const ctx = canvas.getContext("2d");
|
|
862
|
+
if (!ctx) {
|
|
863
|
+
reject(new Error("Failed to get canvas 2D context"));
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
let width = img.width;
|
|
867
|
+
let height = img.height;
|
|
868
|
+
if (width > height) {
|
|
869
|
+
if (width > maxWidth) {
|
|
870
|
+
height = Math.round(height *= maxWidth / width);
|
|
871
|
+
width = maxWidth;
|
|
872
|
+
}
|
|
873
|
+
} else {
|
|
874
|
+
if (height > maxHeight) {
|
|
875
|
+
width = Math.round(width *= maxHeight / height);
|
|
876
|
+
height = maxHeight;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
canvas.width = width;
|
|
880
|
+
canvas.height = height;
|
|
881
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
882
|
+
canvas.toBlob(
|
|
883
|
+
(blob) => {
|
|
884
|
+
if (blob) resolve(blob);
|
|
885
|
+
else reject(new Error("Image compression failed."));
|
|
886
|
+
},
|
|
887
|
+
"image/jpeg",
|
|
888
|
+
quality
|
|
889
|
+
);
|
|
890
|
+
};
|
|
891
|
+
img.onerror = () => reject(new Error("Failed to load image."));
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
async function prepareImage(imageFile) {
|
|
895
|
+
const compressedFile = await resizeImage(imageFile);
|
|
896
|
+
return toBase64(compressedFile);
|
|
897
|
+
}
|
|
898
|
+
function toBase64(file) {
|
|
899
|
+
return new Promise((resolve, reject) => {
|
|
900
|
+
const reader = new FileReader();
|
|
901
|
+
reader.readAsDataURL(file);
|
|
902
|
+
reader.onload = () => resolve(reader.result.split(",")[1]);
|
|
903
|
+
reader.onerror = (error) => reject(error);
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// src/utils/anymals/useUploadAnymalImage.ts
|
|
908
|
+
function useUploadAnymalImage() {
|
|
909
|
+
return useCallback8(
|
|
910
|
+
async (imageFile, type, idToken, publicKey, authServiceBaseUrl) => {
|
|
911
|
+
if (!imageFile || !idToken) {
|
|
912
|
+
return {
|
|
913
|
+
success: false,
|
|
914
|
+
message: "No image file selected or not authenticated.",
|
|
915
|
+
url: null,
|
|
916
|
+
type
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
try {
|
|
920
|
+
const base64Image = await prepareImage(imageFile);
|
|
921
|
+
const payload = {
|
|
922
|
+
appPubKey: publicKey,
|
|
923
|
+
imageData: base64Image,
|
|
924
|
+
imageName: imageFile.name.split(".")[0]
|
|
925
|
+
};
|
|
926
|
+
const response = await fetch(`${authServiceBaseUrl}/process-image`, {
|
|
927
|
+
method: "POST",
|
|
928
|
+
headers: {
|
|
929
|
+
"Content-Type": "application/json",
|
|
930
|
+
Authorization: `Bearer ${idToken}`
|
|
931
|
+
},
|
|
932
|
+
body: JSON.stringify(payload)
|
|
933
|
+
});
|
|
934
|
+
const data = await response.json();
|
|
935
|
+
if (response.ok) {
|
|
936
|
+
return {
|
|
937
|
+
success: true,
|
|
938
|
+
message: "Image uploaded successfully.",
|
|
939
|
+
url: data.ipfsUrl,
|
|
940
|
+
type
|
|
941
|
+
};
|
|
942
|
+
} else {
|
|
943
|
+
return {
|
|
944
|
+
success: false,
|
|
945
|
+
message: "Image failed to upload.",
|
|
946
|
+
url: null,
|
|
947
|
+
type
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
} catch (error) {
|
|
951
|
+
return {
|
|
952
|
+
success: false,
|
|
953
|
+
message: `An error occurred during image upload: ${error.message}`,
|
|
954
|
+
url: null,
|
|
955
|
+
type
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
},
|
|
959
|
+
[]
|
|
960
|
+
);
|
|
961
|
+
}
|
|
779
962
|
export {
|
|
780
963
|
useAddAnymalToDatabase,
|
|
781
964
|
useDeleteAnymalFromDatabase,
|
|
965
|
+
useFetchBalance,
|
|
782
966
|
useMintAnymalNFT,
|
|
783
967
|
useSaveAnymalMetadata,
|
|
968
|
+
useUpdateAnymalWithNFT,
|
|
969
|
+
useUploadAnymalImage,
|
|
784
970
|
useVerifyAccount
|
|
785
971
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export function resizeImage(
|
|
2
|
+
file: File,
|
|
3
|
+
maxWidth = 800,
|
|
4
|
+
maxHeight = 800,
|
|
5
|
+
quality = 0.7
|
|
6
|
+
): Promise<Blob> {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const img = new Image();
|
|
9
|
+
img.src = URL.createObjectURL(file);
|
|
10
|
+
img.onload = () => {
|
|
11
|
+
const canvas = document.createElement("canvas");
|
|
12
|
+
const ctx = canvas.getContext("2d");
|
|
13
|
+
|
|
14
|
+
if (!ctx) {
|
|
15
|
+
reject(new Error("Failed to get canvas 2D context"));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let width = img.width;
|
|
20
|
+
let height = img.height;
|
|
21
|
+
|
|
22
|
+
if (width > height) {
|
|
23
|
+
if (width > maxWidth) {
|
|
24
|
+
height = Math.round((height *= maxWidth / width));
|
|
25
|
+
width = maxWidth;
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
if (height > maxHeight) {
|
|
29
|
+
width = Math.round((width *= maxHeight / height));
|
|
30
|
+
height = maxHeight;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
canvas.width = width;
|
|
35
|
+
canvas.height = height;
|
|
36
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
37
|
+
|
|
38
|
+
canvas.toBlob(
|
|
39
|
+
(blob) => {
|
|
40
|
+
if (blob) resolve(blob);
|
|
41
|
+
else reject(new Error("Image compression failed."));
|
|
42
|
+
},
|
|
43
|
+
"image/jpeg",
|
|
44
|
+
quality
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
img.onerror = () => reject(new Error("Failed to load image."));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function prepareImage(imageFile: File): Promise<string> {
|
|
52
|
+
const compressedFile = (await resizeImage(imageFile)) as Blob;
|
|
53
|
+
return toBase64(compressedFile);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function toBase64(file: Blob): Promise<string> {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
const reader = new FileReader();
|
|
59
|
+
reader.readAsDataURL(file);
|
|
60
|
+
reader.onload = () => resolve((reader.result as string).split(",")[1]);
|
|
61
|
+
reader.onerror = (error) => reject(error);
|
|
62
|
+
});
|
|
63
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export * from "./utils/useVerifyAccount";
|
|
1
|
+
export * from "./utils/account/useVerifyAccount";
|
|
2
2
|
export * from "./utils/anymals/useMintAnymalNFT";
|
|
3
3
|
export * from "./utils/anymals/useAddAnymalToDatabase";
|
|
4
4
|
export * from "./utils/anymals/useDeleteAnymalFromDatabase";
|
|
5
5
|
export * from "./utils/anymals/useSaveAnymalMetadata";
|
|
6
|
+
export * from "./utils/anymals/useUpdateAnymalWithNFT";
|
|
7
|
+
export * from "./utils/balance/useFetchBalance";
|
|
8
|
+
export * from "./utils/anymals/useUploadAnymalImage";
|
|
6
9
|
export * from "./types/Anymal";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback } from "react";
|
|
2
2
|
import { encodeFunctionData, parseGwei } from "viem";
|
|
3
|
-
import { VERIFY_ACCOUNT_ABI } from "
|
|
3
|
+
import { VERIFY_ACCOUNT_ABI } from "../../helpers/BlockchainAbiHelper";
|
|
4
4
|
|
|
5
5
|
export function useVerifyAccount() {
|
|
6
6
|
return useCallback(
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { prepareImage } from "../../helpers/UploadImageHelper";
|
|
3
|
+
|
|
4
|
+
export function useUploadAnymalImage() {
|
|
5
|
+
return useCallback(
|
|
6
|
+
async (
|
|
7
|
+
imageFile: File,
|
|
8
|
+
type: string,
|
|
9
|
+
idToken: string,
|
|
10
|
+
publicKey: string,
|
|
11
|
+
authServiceBaseUrl: string
|
|
12
|
+
) => {
|
|
13
|
+
if (!imageFile || !idToken) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
message: "No image file selected or not authenticated.",
|
|
17
|
+
url: null,
|
|
18
|
+
type,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const base64Image = await prepareImage(imageFile);
|
|
24
|
+
|
|
25
|
+
const payload = {
|
|
26
|
+
appPubKey: publicKey,
|
|
27
|
+
imageData: base64Image,
|
|
28
|
+
imageName: imageFile.name.split(".")[0],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const response = await fetch(`${authServiceBaseUrl}/process-image`, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: {
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
Authorization: `Bearer ${idToken}`,
|
|
36
|
+
},
|
|
37
|
+
body: JSON.stringify(payload),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
|
|
42
|
+
if (response.ok) {
|
|
43
|
+
return {
|
|
44
|
+
success: true,
|
|
45
|
+
message: "Image uploaded successfully.",
|
|
46
|
+
url: data.ipfsUrl,
|
|
47
|
+
type,
|
|
48
|
+
};
|
|
49
|
+
} else {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
message: "Image failed to upload.",
|
|
53
|
+
url: null,
|
|
54
|
+
type,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
message: `An error occurred during image upload: ${
|
|
61
|
+
(error as Error).message
|
|
62
|
+
}`,
|
|
63
|
+
url: null,
|
|
64
|
+
type,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
[]
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { erc20Abi, getAddress } from "viem";
|
|
3
|
+
|
|
4
|
+
export function useFetchBalance() {
|
|
5
|
+
return useCallback(
|
|
6
|
+
async (
|
|
7
|
+
publicClient: any,
|
|
8
|
+
walletAddress: string,
|
|
9
|
+
kibbleTokenAddress: string
|
|
10
|
+
) => {
|
|
11
|
+
try {
|
|
12
|
+
const balance = await publicClient.readContract({
|
|
13
|
+
address: getAddress(kibbleTokenAddress),
|
|
14
|
+
abi: erc20Abi,
|
|
15
|
+
functionName: "balanceOf",
|
|
16
|
+
args: [getAddress(walletAddress)],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return Number(balance);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error("Failed to fetch token balance:", error);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
[]
|
|
25
|
+
);
|
|
26
|
+
}
|