@zoralabs/coins-sdk 0.2.4 → 0.2.6

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/actions/createCoin.d.ts +1 -1
  3. package/dist/actions/createCoin.d.ts.map +1 -1
  4. package/dist/actions/tradeCoin.d.ts +52 -0
  5. package/dist/actions/tradeCoin.d.ts.map +1 -0
  6. package/dist/api/api-key.d.ts +2 -1
  7. package/dist/api/api-key.d.ts.map +1 -1
  8. package/dist/api/internal.d.ts +2 -2
  9. package/dist/api/internal.d.ts.map +1 -1
  10. package/dist/client/sdk.gen.d.ts +77 -1
  11. package/dist/client/sdk.gen.d.ts.map +1 -1
  12. package/dist/client/types.gen.d.ts +156 -0
  13. package/dist/client/types.gen.d.ts.map +1 -1
  14. package/dist/index.cjs +405 -1
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.ts +3 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +404 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/metadata/cleanAndValidateMetadataURI.d.ts +1 -1
  21. package/dist/metadata/cleanAndValidateMetadataURI.d.ts.map +1 -1
  22. package/dist/metadata/index.d.ts +1 -1
  23. package/dist/metadata/index.d.ts.map +1 -1
  24. package/dist/metadata/validateMetadataURIContent.d.ts +1 -1
  25. package/dist/metadata/validateMetadataURIContent.d.ts.map +1 -1
  26. package/dist/uploader/index.d.ts +10 -0
  27. package/dist/uploader/index.d.ts.map +1 -0
  28. package/dist/uploader/metadata.d.ts +44 -0
  29. package/dist/uploader/metadata.d.ts.map +1 -0
  30. package/dist/uploader/providers/zora.d.ts +18 -0
  31. package/dist/uploader/providers/zora.d.ts.map +1 -0
  32. package/dist/uploader/types.d.ts +21 -0
  33. package/dist/uploader/types.d.ts.map +1 -0
  34. package/package.json +1 -1
  35. package/src/actions/createCoin.ts +2 -1
  36. package/src/actions/tradeCoin.ts +230 -0
  37. package/src/api/api-key.ts +5 -1
  38. package/src/api/internal.ts +3 -3
  39. package/src/client/sdk.gen.ts +26 -0
  40. package/src/client/types.gen.ts +161 -0
  41. package/src/index.ts +6 -0
  42. package/src/metadata/cleanAndValidateMetadataURI.ts +1 -5
  43. package/src/metadata/index.ts +1 -4
  44. package/src/metadata/validateMetadataURIContent.ts +2 -4
  45. package/src/uploader/index.ts +16 -0
  46. package/src/uploader/metadata.ts +214 -0
  47. package/src/uploader/providers/zora.ts +86 -0
  48. package/src/uploader/tests/metadata.test.ts +331 -0
  49. package/src/uploader/tests/providers.test.ts +131 -0
  50. package/src/uploader/types.ts +27 -0
package/dist/index.cjs CHANGED
@@ -532,6 +532,9 @@ async function updatePayoutRecipient(args, walletClient, publicClient) {
532
532
  return { hash, receipt, payoutRecipientUpdated };
533
533
  }
534
534
 
535
+ // src/actions/tradeCoin.ts
536
+
537
+
535
538
  // src/client/client.gen.ts
536
539
 
537
540
 
@@ -580,6 +583,22 @@ var getCoins = (options) => {
580
583
  ...options
581
584
  });
582
585
  };
586
+ var setCreateUploadJwt = (options) => {
587
+ return (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _11 => _11.client]), () => ( client))).post({
588
+ security: [
589
+ {
590
+ name: "api-key",
591
+ type: "apiKey"
592
+ }
593
+ ],
594
+ url: "/createUploadJWT",
595
+ ...options,
596
+ headers: {
597
+ "Content-Type": "application/json",
598
+ ..._optionalChain([options, 'optionalAccess', _12 => _12.headers])
599
+ }
600
+ });
601
+ };
583
602
  var getExplore = (options) => {
584
603
  return (_nullishCoalesce(options.client, () => ( client))).get({
585
604
  security: [
@@ -628,12 +647,173 @@ var getProfileCoins = (options) => {
628
647
  ...options
629
648
  });
630
649
  };
650
+ var postQuote = (options) => {
651
+ return (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _13 => _13.client]), () => ( client))).post({
652
+ security: [
653
+ {
654
+ name: "api-key",
655
+ type: "apiKey"
656
+ }
657
+ ],
658
+ url: "/quote",
659
+ ...options,
660
+ headers: {
661
+ "Content-Type": "application/json",
662
+ ..._optionalChain([options, 'optionalAccess', _14 => _14.headers])
663
+ }
664
+ });
665
+ };
666
+
667
+ // src/actions/tradeCoin.ts
668
+
669
+
670
+
671
+
672
+
673
+ function convertBigIntToString(permit) {
674
+ return {
675
+ ...permit,
676
+ details: {
677
+ ...permit.details,
678
+ amount: `${permit.details.amount}`
679
+ },
680
+ sigDeadline: `${permit.sigDeadline}`
681
+ };
682
+ }
683
+ var PERMIT_SINGLE_TYPES = {
684
+ PermitSingle: [
685
+ { name: "details", type: "PermitDetails" },
686
+ { name: "spender", type: "address" },
687
+ { name: "sigDeadline", type: "uint256" }
688
+ ],
689
+ PermitDetails: [
690
+ { name: "token", type: "address" },
691
+ { name: "amount", type: "uint160" },
692
+ { name: "expiration", type: "uint48" },
693
+ { name: "nonce", type: "uint48" }
694
+ ]
695
+ };
696
+ async function tradeCoin(tradeParameters, walletClient, account, publicClient, validateTransaction = true) {
697
+ const quote = await createTradeCall(tradeParameters);
698
+ const signatures = [];
699
+ if (quote.permits) {
700
+ for (const permit of quote.permits) {
701
+ const [, nonce] = await publicClient.readContract({
702
+ abi: _protocoldeployments.permit2ABI,
703
+ address: _protocoldeployments.permit2Address[_chains.base.id],
704
+ functionName: "allowance",
705
+ args: [
706
+ permit.permit.details.token,
707
+ account.address,
708
+ permit.permit.spender
709
+ ]
710
+ });
711
+ const permitToken = permit.permit.details.token;
712
+ const allowance = await publicClient.readContract({
713
+ abi: _viem.erc20Abi,
714
+ address: permitToken,
715
+ functionName: "allowance",
716
+ args: [permitToken, _protocoldeployments.permit2Address[_chains.base.id]]
717
+ });
718
+ if (allowance < BigInt(permit.permit.details.amount)) {
719
+ const approvalTx = await walletClient.writeContract({
720
+ abi: _viem.erc20Abi,
721
+ address: permitToken,
722
+ functionName: "approve",
723
+ chain: _chains.base,
724
+ args: [_protocoldeployments.permit2Address[_chains.base.id], _viem.maxUint256],
725
+ account
726
+ });
727
+ await publicClient.waitForTransactionReceipt({
728
+ hash: approvalTx
729
+ });
730
+ }
731
+ const message = {
732
+ details: {
733
+ token: permit.permit.details.token,
734
+ amount: BigInt(permit.permit.details.amount),
735
+ expiration: Number(permit.permit.details.expiration),
736
+ nonce
737
+ },
738
+ spender: permit.permit.spender,
739
+ sigDeadline: BigInt(permit.permit.sigDeadline)
740
+ };
741
+ const signature = await walletClient.signTypedData({
742
+ domain: {
743
+ name: "Permit2",
744
+ chainId: _chains.base.id,
745
+ verifyingContract: _protocoldeployments.permit2Address[_chains.base.id]
746
+ },
747
+ primaryType: "PermitSingle",
748
+ types: PERMIT_SINGLE_TYPES,
749
+ message,
750
+ account
751
+ });
752
+ signatures.push({
753
+ signature,
754
+ permit: convertBigIntToString(message)
755
+ });
756
+ }
757
+ }
758
+ const newQuote = await createTradeCall({
759
+ ...tradeParameters,
760
+ signatures
761
+ });
762
+ const call = {
763
+ to: newQuote.call.target,
764
+ data: newQuote.call.data,
765
+ value: BigInt(newQuote.call.value),
766
+ chain: _chains.base,
767
+ account
768
+ };
769
+ if (validateTransaction) {
770
+ await publicClient.call(call);
771
+ }
772
+ const gasEstimate = validateTransaction ? await publicClient.estimateGas(call) : 10000000n;
773
+ const gasPrice = await publicClient.getGasPrice();
774
+ const tx = await walletClient.sendTransaction({
775
+ ...call,
776
+ gasPrice,
777
+ gas: gasEstimate
778
+ });
779
+ const receipt = await publicClient.waitForTransactionReceipt({
780
+ hash: tx
781
+ });
782
+ return receipt;
783
+ }
784
+ async function createTradeCall(tradeParameters) {
785
+ if (tradeParameters.slippage && tradeParameters.slippage > 1) {
786
+ throw new Error("Slippage must be less than 1, max 0.99");
787
+ }
788
+ if (tradeParameters.amountIn === BigInt(0)) {
789
+ throw new Error("Amount in must be greater than 0");
790
+ }
791
+ const quote = await postQuote({
792
+ body: {
793
+ tokenIn: tradeParameters.sell,
794
+ tokenOut: tradeParameters.buy,
795
+ amountIn: tradeParameters.amountIn.toString(),
796
+ slippage: tradeParameters.slippage,
797
+ chainId: _chains.base.id,
798
+ sender: tradeParameters.sender,
799
+ recipient: tradeParameters.recipient || tradeParameters.sender,
800
+ signatures: tradeParameters.signatures
801
+ }
802
+ });
803
+ if (!quote.data) {
804
+ throw new Error("Quote failed");
805
+ }
806
+ return quote.data;
807
+ }
631
808
 
632
809
  // src/api/api-key.ts
633
810
  var apiKey;
634
811
  function setApiKey(key) {
635
812
  apiKey = key;
636
813
  }
814
+ function getApiKey() {
815
+ return apiKey;
816
+ }
637
817
  function getApiKeyMeta() {
638
818
  if (!apiKey) {
639
819
  return {};
@@ -704,6 +884,230 @@ var getCoinsNew = (query = {}, options) => createExploreQuery(query, "NEW", opti
704
884
  var getCoinsLastTraded = (query = {}, options) => createExploreQuery(query, "LAST_TRADED", options);
705
885
  var getCoinsLastTradedUnique = (query = {}, options) => createExploreQuery(query, "LAST_TRADED_UNIQUE", options);
706
886
 
887
+ // src/uploader/metadata.ts
888
+ function validateImageMimeType(mimeType) {
889
+ if (![
890
+ "image/png",
891
+ "image/jpeg",
892
+ "image/jpg",
893
+ "image/gif",
894
+ "image/svg+xml"
895
+ ].includes(mimeType)) {
896
+ throw new Error("Image must be a PNG, JPEG, JPG, GIF or SVG");
897
+ }
898
+ }
899
+ function getURLFromUploadResult(uploadResult) {
900
+ return new URL(uploadResult.url);
901
+ }
902
+ var CoinMetadataBuilder = class {
903
+ withName(name) {
904
+ this.name = name;
905
+ if (typeof name !== "string") {
906
+ throw new Error("Name must be a string");
907
+ }
908
+ return this;
909
+ }
910
+ withSymbol(symbol) {
911
+ this.symbol = symbol;
912
+ if (typeof symbol !== "string") {
913
+ throw new Error("Symbol must be a string");
914
+ }
915
+ return this;
916
+ }
917
+ withDescription(description) {
918
+ this.description = description;
919
+ if (typeof description !== "string") {
920
+ throw new Error("Description must be a string");
921
+ }
922
+ return this;
923
+ }
924
+ withImage(image) {
925
+ if (this.imageURL) {
926
+ throw new Error("Image URL already set");
927
+ }
928
+ if (!(image instanceof File)) {
929
+ throw new Error("Image must be a File");
930
+ }
931
+ validateImageMimeType(image.type);
932
+ this.imageFile = image;
933
+ return this;
934
+ }
935
+ withImageURI(imageURI) {
936
+ if (this.imageFile) {
937
+ throw new Error("Image file already set");
938
+ }
939
+ if (typeof imageURI !== "string") {
940
+ throw new Error("Image URI must be a string");
941
+ }
942
+ const url = new URL(imageURI);
943
+ this.imageURL = url;
944
+ return this;
945
+ }
946
+ withProperties(properties) {
947
+ for (const [key, value] of Object.entries(properties)) {
948
+ if (typeof key !== "string") {
949
+ throw new Error("Property key must be a string");
950
+ }
951
+ if (typeof value !== "string") {
952
+ throw new Error("Property value must be a string");
953
+ }
954
+ }
955
+ if (!this.properties) {
956
+ this.properties = {};
957
+ }
958
+ this.properties = { ...this.properties, ...properties };
959
+ return this;
960
+ }
961
+ withMedia(media) {
962
+ if (this.mediaURL) {
963
+ throw new Error("Media URL already set");
964
+ }
965
+ if (!(media instanceof File)) {
966
+ throw new Error("Media must be a File");
967
+ }
968
+ this.mediaMimeType = media.type;
969
+ this.mediaFile = media;
970
+ return this;
971
+ }
972
+ withMediaURI(mediaURI, mediaMimeType) {
973
+ if (this.mediaFile) {
974
+ throw new Error("Media file already set");
975
+ }
976
+ if (typeof mediaURI !== "string") {
977
+ throw new Error("Media URI must be a string");
978
+ }
979
+ const url = new URL(mediaURI);
980
+ this.mediaURL = url;
981
+ this.mediaMimeType = mediaMimeType;
982
+ return this;
983
+ }
984
+ validate() {
985
+ if (!this.name) {
986
+ throw new Error("Name is required");
987
+ }
988
+ if (!this.symbol) {
989
+ throw new Error("Symbol is required");
990
+ }
991
+ if (!this.imageFile && !this.imageURL) {
992
+ throw new Error("Image is required");
993
+ }
994
+ return this;
995
+ }
996
+ generateMetadata() {
997
+ return {
998
+ name: this.name,
999
+ symbol: this.symbol,
1000
+ description: this.description,
1001
+ image: this.imageURL.toString(),
1002
+ animation_url: _optionalChain([this, 'access', _15 => _15.mediaURL, 'optionalAccess', _16 => _16.toString, 'call', _17 => _17()]),
1003
+ content: this.mediaURL ? {
1004
+ uri: _optionalChain([this, 'access', _18 => _18.mediaURL, 'optionalAccess', _19 => _19.toString, 'call', _20 => _20()]),
1005
+ mime: this.mediaMimeType
1006
+ } : void 0,
1007
+ properties: this.properties
1008
+ };
1009
+ }
1010
+ async upload(uploader) {
1011
+ this.validate();
1012
+ if (this.imageFile) {
1013
+ const uploadResult2 = await uploader.upload(this.imageFile);
1014
+ this.imageURL = getURLFromUploadResult(uploadResult2);
1015
+ }
1016
+ if (this.mediaFile) {
1017
+ const uploadResult2 = await uploader.upload(this.mediaFile);
1018
+ this.mediaURL = getURLFromUploadResult(uploadResult2);
1019
+ }
1020
+ const metadata = this.generateMetadata();
1021
+ const uploadResult = await uploader.upload(
1022
+ new File([JSON.stringify(metadata)], "metadata.json", {
1023
+ type: "application/json"
1024
+ })
1025
+ );
1026
+ return {
1027
+ url: getURLFromUploadResult(uploadResult).toString(),
1028
+ createMetadataParameters: {
1029
+ name: this.name,
1030
+ symbol: this.symbol,
1031
+ uri: uploadResult.url
1032
+ },
1033
+ metadata
1034
+ };
1035
+ }
1036
+ };
1037
+ function createMetadataBuilder() {
1038
+ return new CoinMetadataBuilder();
1039
+ }
1040
+
1041
+ // src/api/internal.ts
1042
+ var setCreateUploadJwt2 = async (body, options) => {
1043
+ return await setCreateUploadJwt({
1044
+ body,
1045
+ ...getApiKeyMeta(),
1046
+ ...options
1047
+ });
1048
+ };
1049
+
1050
+ // src/uploader/providers/zora.ts
1051
+ var ZoraUploader = class {
1052
+ constructor(creatorAddress) {
1053
+ this.creatorAddress = creatorAddress;
1054
+ if (!getApiKey()) {
1055
+ throw new Error("API key is required for metadata interactions");
1056
+ }
1057
+ }
1058
+ async getJWTApiKey() {
1059
+ if (this.jwtApiKey && this.jwtApiKeyExpiresAt && this.jwtApiKeyExpiresAt > Date.now()) {
1060
+ return this.jwtApiKey;
1061
+ }
1062
+ this.jwtApiKeyExpiresAt = Date.now() + 1e3 * 60 * 60;
1063
+ const response = await setCreateUploadJwt2({
1064
+ creatorAddress: this.creatorAddress
1065
+ });
1066
+ this.jwtApiKey = _optionalChain([response, 'access', _21 => _21.data, 'optionalAccess', _22 => _22.createUploadJwtFromApiKey]);
1067
+ if (!this.jwtApiKey) {
1068
+ throw new Error("Failed to create upload JWT");
1069
+ }
1070
+ return this.jwtApiKey;
1071
+ }
1072
+ async upload(file) {
1073
+ const jwtApiKey = await this.getJWTApiKey();
1074
+ const formData = new FormData();
1075
+ formData.append("file", file, file.name);
1076
+ const response = await fetch(
1077
+ "https://ipfs-uploader.zora.co/api/v0/add?cid-version=1",
1078
+ {
1079
+ method: "POST",
1080
+ headers: {
1081
+ Authorization: `Bearer ${jwtApiKey}`,
1082
+ Accept: "*/*"
1083
+ },
1084
+ body: formData
1085
+ }
1086
+ );
1087
+ if (!response.ok) {
1088
+ console.error(await response.text());
1089
+ throw new Error(`Failed to upload file: ${response.statusText}`);
1090
+ }
1091
+ const data = await response.json();
1092
+ return {
1093
+ url: `ipfs://${data.cid}`,
1094
+ size: data.size,
1095
+ mimeType: data.mimeType
1096
+ };
1097
+ }
1098
+ };
1099
+ function createZoraUploaderForCreator(creatorAddress) {
1100
+ return new ZoraUploader(creatorAddress);
1101
+ }
1102
+
1103
+
1104
+
1105
+
1106
+
1107
+
1108
+
1109
+
1110
+
707
1111
 
708
1112
 
709
1113
 
@@ -730,5 +1134,5 @@ var getCoinsLastTradedUnique = (query = {}, options) => createExploreQuery(query
730
1134
 
731
1135
 
732
1136
 
733
- exports.DeployCurrency = DeployCurrency; exports.InitialPurchaseCurrency = InitialPurchaseCurrency; exports.cleanAndValidateMetadataURI = cleanAndValidateMetadataURI; exports.createCoin = createCoin; exports.createCoinCall = createCoinCall; exports.getCoin = getCoin2; exports.getCoinComments = getCoinComments2; exports.getCoinCreateFromLogs = getCoinCreateFromLogs; exports.getCoins = getCoins2; exports.getCoinsLastTraded = getCoinsLastTraded; exports.getCoinsLastTradedUnique = getCoinsLastTradedUnique; exports.getCoinsMostValuable = getCoinsMostValuable; exports.getCoinsNew = getCoinsNew; exports.getCoinsTopGainers = getCoinsTopGainers; exports.getCoinsTopVolume24h = getCoinsTopVolume24h; exports.getOnchainCoinDetails = getOnchainCoinDetails; exports.getProfile = getProfile2; exports.getProfileBalances = getProfileBalances2; exports.getProfileCoins = getProfileCoins2; exports.setApiKey = setApiKey; exports.updateCoinURI = updateCoinURI; exports.updateCoinURICall = updateCoinURICall; exports.updatePayoutRecipient = updatePayoutRecipient; exports.updatePayoutRecipientCall = updatePayoutRecipientCall; exports.validateMetadataJSON = validateMetadataJSON; exports.validateMetadataURIContent = validateMetadataURIContent;
1137
+ exports.CoinMetadataBuilder = CoinMetadataBuilder; exports.DeployCurrency = DeployCurrency; exports.InitialPurchaseCurrency = InitialPurchaseCurrency; exports.ZoraUploader = ZoraUploader; exports.cleanAndValidateMetadataURI = cleanAndValidateMetadataURI; exports.createCoin = createCoin; exports.createCoinCall = createCoinCall; exports.createMetadataBuilder = createMetadataBuilder; exports.createTradeCall = createTradeCall; exports.createZoraUploaderForCreator = createZoraUploaderForCreator; exports.getCoin = getCoin2; exports.getCoinComments = getCoinComments2; exports.getCoinCreateFromLogs = getCoinCreateFromLogs; exports.getCoins = getCoins2; exports.getCoinsLastTraded = getCoinsLastTraded; exports.getCoinsLastTradedUnique = getCoinsLastTradedUnique; exports.getCoinsMostValuable = getCoinsMostValuable; exports.getCoinsNew = getCoinsNew; exports.getCoinsTopGainers = getCoinsTopGainers; exports.getCoinsTopVolume24h = getCoinsTopVolume24h; exports.getOnchainCoinDetails = getOnchainCoinDetails; exports.getProfile = getProfile2; exports.getProfileBalances = getProfileBalances2; exports.getProfileCoins = getProfileCoins2; exports.getURLFromUploadResult = getURLFromUploadResult; exports.setApiKey = setApiKey; exports.tradeCoin = tradeCoin; exports.updateCoinURI = updateCoinURI; exports.updateCoinURICall = updateCoinURICall; exports.updatePayoutRecipient = updatePayoutRecipient; exports.updatePayoutRecipientCall = updatePayoutRecipientCall; exports.validateImageMimeType = validateImageMimeType; exports.validateMetadataJSON = validateMetadataJSON; exports.validateMetadataURIContent = validateMetadataURIContent;
734
1138
  //# sourceMappingURL=index.cjs.map