diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d9d457..3c2f539 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Linkdrop SDK + +## 2.1.3 +- updates for src=d param (getLinks method of batch) + +## 2.1.2 +- updates for claimHostUrl param (getLinks method of batch) + +## 2.1.1 +- added testnets apiUrl + +## 2.1.0 +- added apiKey as param for LinkdropSDK + ## 2.0.9 - added src param to link (src=d) diff --git a/README.md b/README.md index b63d9b3..31274d2 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,14 @@ import LinkdropSDK from 'linkdrop-sdk' To use SDK on a tesnet: ```ts // initializing Linkdrop SDK on a testnet (Goerli or Mumbai) -const sdk = new LinkdropSDK({ mode: 'testnets' }); +const apiKey = /* to request an API key, please contact us at hi@linkdrop.io */ +const sdk = new LinkdropSDK({ mode: 'testnets', apiKey }); ``` To use SDK on a production network (Ethereum Mainnet or Polygon): ```ts // initializing Linkdrop SDK on a production network -const sdk = new LinkdropSDK(); +const apiKey = /* to request an API key, please contact us at hi@linkdrop.io */ +const sdk = new LinkdropSDK({ apiKey }); ``` ## Claim methods (Can be used on Front-end & Back-end) @@ -248,6 +250,16 @@ To fetch all links created for that batch, use the `batch.getLinks` method: const links = await batch.getLinks() ``` +Response data includes claim links in format `https://claim.linkdrop.io/#/...` +If you need links in custom format please provide optional parameter to `getLinks` method +```ts +const links = await batch.getLinks('https://wallet.coinbase.com/claim?tk=code&k=&c=&v=3') +``` + +As a result you will get claim links with actual claim code (``) and chain id (``) + + + ### Deactivating / reactivating links #### Deactivate Link diff --git a/package.json b/package.json index f322463..f582269 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "linkdrop-sdk", - "version": "2.0.9", + "version": "2.1.3", "main": "dist/index.js", "types": "dist/index.d.ts", "files": [ diff --git a/src/api/batch/index.ts b/src/api/batch/index.ts index 6b4cce0..44724c1 100644 --- a/src/api/batch/index.ts +++ b/src/api/batch/index.ts @@ -5,33 +5,36 @@ import { defineRequestKeyHeader } from '../../helpers' const requests: TRequests = { getBatches: ( apiHost, + apiKey, campaignSig, campaignId ) => { - const headers = defineRequestKeyHeader(campaignSig) + const headers = defineRequestKeyHeader(campaignSig, apiKey) return axios.get(`${apiHost}/api/v2/dashboard/linkdrop/campaigns/${campaignId}/batches`, { headers, }) }, getBatch: ( apiHost, + apiKey, campaignSig, campaignId, batchId ) => { - const headers = defineRequestKeyHeader(campaignSig) + const headers = defineRequestKeyHeader(campaignSig, apiKey) return axios.get(`${apiHost}/api/v2/dashboard/linkdrop/campaigns/${campaignId}/batches/${batchId}`, { headers, }) }, createBatch: ( apiHost, + apiKey, campaignSig, campaignId, claimLinks, batchDescription ) => { - const headers = defineRequestKeyHeader(campaignSig) + const headers = defineRequestKeyHeader(campaignSig, apiKey) return axios.post(`${apiHost}/api/v2/dashboard/linkdrop/campaigns/${campaignId}/save-batch`, { claim_links: claimLinks, batch_description: batchDescription @@ -41,12 +44,13 @@ const requests: TRequests = { }, addLinks: ( apiHost, + apiKey, campaignSig, campaignId, batchId, claimLinks, ) => { - const headers = defineRequestKeyHeader(campaignSig) + const headers = defineRequestKeyHeader(campaignSig, apiKey) return axios.post(`${apiHost}/api/v2/dashboard/linkdrop/campaigns/${campaignId}/batches/${batchId}/add-links `, { claim_links: claimLinks }, { diff --git a/src/api/batch/types.ts b/src/api/batch/types.ts index aa92bca..6c734ab 100644 --- a/src/api/batch/types.ts +++ b/src/api/batch/types.ts @@ -29,6 +29,7 @@ type TAddLinksResponse = { export type TGetBatches = ( apiHost: string, + apiKey: string, campaignSig: string, campaignId: string ) => Promise< @@ -39,6 +40,7 @@ export type TGetBatches = ( export type TGetBatch = ( apiHost: string, + apiKey: string, campaignSig: string, campaignId: string, batchId: string @@ -50,6 +52,7 @@ export type TGetBatch = ( export type TCreateBatch = ( apiHost: string, + apiKey: string, campaignSig: string, campaignId: string, claimLinks: TLinkItem[], @@ -62,6 +65,7 @@ export type TCreateBatch = ( export type TAddLinks = ( apiHost: string, + apiKey: string, campaignSig: string, campaignId: string, batchId: string, diff --git a/src/api/campaign/index.ts b/src/api/campaign/index.ts index f94d708..d246fdb 100644 --- a/src/api/campaign/index.ts +++ b/src/api/campaign/index.ts @@ -5,10 +5,11 @@ import { defineRequestKeyHeader } from '../../helpers' const requests: TRequests = { getCampaign: ( apiHost, + apiKey, campaignSig, campaignId ) => { - const headers = defineRequestKeyHeader(campaignSig) + const headers = defineRequestKeyHeader(campaignSig, apiKey) return axios.get(`${apiHost}/api/v2/dashboard/linkdrop/campaigns/${campaignId}`, { headers }) diff --git a/src/api/campaign/types.ts b/src/api/campaign/types.ts index 51b0a6b..c2f851b 100644 --- a/src/api/campaign/types.ts +++ b/src/api/campaign/types.ts @@ -8,6 +8,7 @@ type TGetCampaignResponse = { export type TGetCampaign = ( apiHost: string, + apiKey: string, campaignSig: string, campaignId: string, ) => Promise< diff --git a/src/api/link/index.ts b/src/api/link/index.ts index 066fb50..43ffda6 100644 --- a/src/api/link/index.ts +++ b/src/api/link/index.ts @@ -17,20 +17,22 @@ const requests: TRequests = { }, deactivateLink: ( apiHost, + apiKey, campaignSig, linkId ) => { - const headers = defineRequestKeyHeader(campaignSig) + const headers = defineRequestKeyHeader(campaignSig, apiKey) return axios.post(`${apiHost}/api/v2/dashboard/linkdrop/claim-links/${linkId}/deactivate`, {}, { headers }) }, reactivateLink: ( apiHost, + apiKey, campaignSig, linkId ) => { - const headers = defineRequestKeyHeader(campaignSig) + const headers = defineRequestKeyHeader(campaignSig, apiKey) return axios.post(`${apiHost}/api/v2/dashboard/linkdrop/claim-links/${linkId}/reactivate`, {}, { headers }) diff --git a/src/api/link/types.ts b/src/api/link/types.ts index ec5fabb..11031be 100644 --- a/src/api/link/types.ts +++ b/src/api/link/types.ts @@ -48,6 +48,7 @@ export type TGetLinkStatus = ( export type TDeactivateLink = ( apiHost: string, + apiKey: string, campaignSig: string, linkId: string ) => Promise< @@ -69,6 +70,7 @@ export type TRedeemLink = ( export type TReactivateLink = ( apiHost: string, + apiKey: string, campaignSig: string, linkId: string ) => Promise< diff --git a/src/configs/index.ts b/src/configs/index.ts index 461b20e..173d707 100644 --- a/src/configs/index.ts +++ b/src/configs/index.ts @@ -1,5 +1,8 @@ export const apiUrl = 'https://dashboard-api.linkdrop.io' -export const testnetsApiUrl = 'https://testnets.dashboard-api.linkdrop.io' +export const testnetsApiUrl = 'https://linkdrop-api-testnets-b0fceb9.zuplo.app' + +export const claimHostUrl = 'https://claim.linkdrop.io' +export const testnetsClaimHostUrl = 'https://testnets.claim.linkdrop.io' export const polygonJSONRPCUrl = 'https://rpc-mainnet.maticvigil.com/v1/ad4cd2ea018ddb1ccd0418ffa43c27b3d99fbd55' export const mainnetJSONRPCUrl = 'https://mainnet.infura.io/v3/620c738fbe1843a18f47ada0e60e738a' diff --git a/src/helpers/define-claim-host-url.ts b/src/helpers/define-claim-host-url.ts new file mode 100644 index 0000000..e82137d --- /dev/null +++ b/src/helpers/define-claim-host-url.ts @@ -0,0 +1,20 @@ +import { claimHostUrl, testnetsClaimHostUrl } from '../configs' +import { TMode } from '../types' + +type TDefineClaimHostUrl = ( + mode: TMode +) => string + +const defineClaimHostUrl: TDefineClaimHostUrl = ( + chainId +) => { + switch (chainId) { + case 'testnets': + return testnetsClaimHostUrl + case 'mainnets': + default: + return claimHostUrl + } +} + +export default defineClaimHostUrl diff --git a/src/helpers/define-request-key-header.ts b/src/helpers/define-request-key-header.ts index 882a665..cbd3f21 100644 --- a/src/helpers/define-request-key-header.ts +++ b/src/helpers/define-request-key-header.ts @@ -1,9 +1,21 @@ -type TDefineRequestKeyHeader = (campaignSig: string) => Record -const defineRequestKeyHeader: TDefineRequestKeyHeader = (campaignSig) => { +type TDefineRequestKeyHeader = ( + campaignSig: string, + apiKey: string +) => Record + +const defineRequestKeyHeader: TDefineRequestKeyHeader = ( + campaignSig, + apiKey +) => { const headers = {} headers[ 'X-CAMPAIGN-KEY' ] = campaignSig + + if (apiKey) { + headers['authorization'] = `Bearer ${apiKey}` + } + return headers } diff --git a/src/helpers/index.ts b/src/helpers/index.ts index b116f64..7964f95 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -10,9 +10,11 @@ import redeemLink from './redeem-link' import getBignumberInterval from './get-bignumber-interval' import defineCampaignSig from './define-campaign-sig' import prepareAsset from './prepare-asset' +import defineClaimHostUrl from './define-claim-host-url' export { parseLinkParams, + defineClaimHostUrl, defineCampaignSig, getBignumberInterval, getLinkParams, diff --git a/src/modules/batch/index.ts b/src/modules/batch/index.ts index 5d20717..ed211c3 100644 --- a/src/modules/batch/index.ts +++ b/src/modules/batch/index.ts @@ -15,6 +15,8 @@ class Batch implements IBatch { claimHostUrl: string campaignData: TCampaignItem signerKey: string + apiKey: string + chainId: number constructor ( batchId: string, @@ -25,7 +27,9 @@ class Batch implements IBatch { campaignData: TCampaignItem, signerKey: string, campaignSig: string, - apiHost: string + apiHost: string, + apiKey: string, + chainId: number ) { this.batchId = batchId this.data = data @@ -36,6 +40,8 @@ class Batch implements IBatch { this.claimHostUrl = claimHostUrl this.campaignData = campaignData this.signerKey = signerKey + this.apiKey = apiKey + this.chainId = chainId } addLinks: TAddLinks = async ( @@ -66,6 +72,7 @@ class Batch implements IBatch { if (!transformedAssets) { return alert('Error with assets') } return await batchesApi.addLinks( this.apiHost, + this.apiKey, this.campaignSig, this.campaignData.campaign_id, this.batchId, @@ -73,17 +80,26 @@ class Batch implements IBatch { ) } - getLinks: TGetLinks = () => { + getLinks: TGetLinks = ( + linkPattern + ) => { if (!this.claimLinks) { return [] } return this.claimLinks.map(link => { const encryptedClaimCode = link.encrypted_claim_code const claimCode = crypto.decrypt(encryptedClaimCode, this.encryptionKey) + + let finalLink = `${this.claimHostUrl}/#/redeem/${claimCode}` + if (linkPattern) { + finalLink = linkPattern.replace('', claimCode) + .replace('', String(this.chainId)) + } + const sourceParam = finalLink.includes('?') ? `&src=d` : '?src=d' return { linkId: link.link_id, claimCode, - claimLink: `${this.claimHostUrl}/#/redeem/${claimCode}?src=d` + claimLink: `${finalLink}${sourceParam}` } }) } diff --git a/src/modules/campaign/index.ts b/src/modules/campaign/index.ts index 2bb040b..2036cfe 100644 --- a/src/modules/campaign/index.ts +++ b/src/modules/campaign/index.ts @@ -19,6 +19,7 @@ class Campaign implements ICampaign { apiHost: string claimHostUrl: string campaignSig: string + apiKey: string constructor ( campaignId: string, @@ -27,7 +28,8 @@ class Campaign implements ICampaign { data: TCampaignItem, claimHostUrl: string, campaignSig: string, - apiHost: string + apiHost: string, + apiKey: string ) { this.campaignId = campaignId this.signerKey = signerKey @@ -36,11 +38,13 @@ class Campaign implements ICampaign { this.claimHostUrl = claimHostUrl this.apiHost = apiHost this.campaignSig = campaignSig + this.apiKey = apiKey } getBatches: TGetBatches = async () => { const campaignData = await batchesApi.getBatches( this.apiHost, + this.apiKey, this.campaignSig, this.campaignId ) @@ -59,6 +63,7 @@ class Campaign implements ICampaign { ) => { const campaignData = await batchesApi.getBatch( this.apiHost, + this.apiKey, this.campaignSig, this.campaignId, batchId @@ -75,7 +80,9 @@ class Campaign implements ICampaign { this.data, this.signerKey, this.campaignSig, - this.apiHost + this.apiHost, + this.apiKey, + this.data.chain_id ) } } @@ -110,6 +117,7 @@ class Campaign implements ICampaign { if (!transformedAssets) { return alert('Error with assets') } const response = await batchesApi.createBatch( this.apiHost, + this.apiKey, this.campaignSig, this.data.campaign_id, transformedAssets, @@ -139,6 +147,7 @@ class Campaign implements ICampaign { const linkData = await linkApi.reactivateLink( this.apiHost, + this.apiKey, this.campaignSig, wallet.address ) @@ -157,6 +166,7 @@ class Campaign implements ICampaign { const linkData = await linkApi.deactivateLink( this.apiHost, + this.apiKey, this.campaignSig, wallet.address ) diff --git a/src/modules/linkdrop-sdk/index.ts b/src/modules/linkdrop-sdk/index.ts index f774372..4203092 100644 --- a/src/modules/linkdrop-sdk/index.ts +++ b/src/modules/linkdrop-sdk/index.ts @@ -1,6 +1,16 @@ -import { ILinkdropSDK, TNetworkName } from '../../types' +import { + ILinkdropSDK, + TNetworkName, + TMode +} from '../../types' import Campaign from '../campaign' -import { defineCampaignSig, getLinkParams, getLinkStatus, redeemLink } from '../../helpers' +import { + defineCampaignSig, + getLinkParams, + getLinkStatus, + redeemLink, + defineClaimHostUrl +} from '../../helpers' import { campaignsApi } from '../../api' import { testnetsApiUrl, @@ -14,6 +24,9 @@ class LinkdropSDK implements ILinkdropSDK { chain: TNetworkName apiHost: string claimHostUrl: string + apiKey: string + mode: TMode + utils = { createLink, computeProxyAddress, @@ -21,19 +34,29 @@ class LinkdropSDK implements ILinkdropSDK { } constructor ({ + apiKey, apiHost, mode, claimHostUrl }: { + apiKey?: string, apiHost?: string, - mode?: 'testnets', + mode?: TMode, claimHostUrl?: string } = {}) { this.claimHostUrl = claimHostUrl || '' + + this.mode = mode || 'mainnets' + + if (!apiKey) { + throw new Error('ApiKey required') + } else { + this.apiKey = apiKey + } if (apiHost) { this.apiHost = apiHost } else { - this.apiHost = mode === 'testnets' ? testnetsApiUrl : apiUrl + this.apiHost = this.mode === 'testnets' ? testnetsApiUrl : apiUrl } } @@ -58,6 +81,7 @@ class LinkdropSDK implements ILinkdropSDK { ) const campaignData = await campaignsApi.getCampaign( this.apiHost, + this.apiKey, campaignSig, campaignId ) @@ -69,9 +93,10 @@ class LinkdropSDK implements ILinkdropSDK { signerKey, encryptionKey, campaign, - this.claimHostUrl, + this.claimHostUrl ? this.claimHostUrl : defineClaimHostUrl(this.mode), campaignSig, - this.apiHost + this.apiHost, + this.apiKey ) } } diff --git a/src/types/index.ts b/src/types/index.ts index 1a7a5ac..5618acc 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -13,10 +13,12 @@ import TAsset from './asset' import TCreateLinkResult from './create-link-result' import TLinkParsed from './parsed-link' import { TLinkStatusResult } from './link-status-result' +import TMode from './mode' export { ILinkdropSDK, TLinkStatusResult, + TMode, TLinkParsed, TLinkItem, TCampaignItem, diff --git a/src/types/mode/index.ts b/src/types/mode/index.ts new file mode 100644 index 0000000..6389e9a --- /dev/null +++ b/src/types/mode/index.ts @@ -0,0 +1,3 @@ +type TMode = 'testnets' | 'mainnets' + +export default TMode \ No newline at end of file diff --git a/src/types/modules/batch/get-links/index.ts b/src/types/modules/batch/get-links/index.ts index b946e20..eccf655 100644 --- a/src/types/modules/batch/get-links/index.ts +++ b/src/types/modules/batch/get-links/index.ts @@ -1,4 +1,6 @@ import { TLinkParsed } from '../../../' -type TGetLinks = () => TLinkParsed[] +type TGetLinks = ( + linkPattern?: string +) => TLinkParsed[] export default TGetLinks \ No newline at end of file