Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pods): implement getExternalUrl function #483

Merged
merged 12 commits into from
Jul 16, 2024
5 changes: 5 additions & 0 deletions .changeset/light-rabbits-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rabbitholegg/questdk-plugin-pods": minor
---

implement getExternalUrl for pods
54 changes: 52 additions & 2 deletions packages/pods/src/Pods.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import {
type MintIntentParams,
} from '@rabbitholegg/questdk-plugin-utils'
import { apply } from '@rabbitholegg/questdk'
import { type Address, parseEther } from 'viem'
import { type Address, parseEther, getAddress, zeroAddress } from 'viem'
import { describe, expect, test, vi } from 'vitest'
import { getMintIntent, mint } from './Pods'
import { getExternalUrl, getMintIntent, mint } from './Pods'
import { failingTestCases, passingTestCases } from './test-setup'
import { EXPECTED_ENCODED_DATA_1155 } from './test-transactions'
import { ZORA_DEPLOYER_ADDRESS } from './contract-addresses'

describe('Given the pods plugin', () => {
describe('When handling the mint', () => {
Expand Down Expand Up @@ -201,3 +202,52 @@ describe('simulateMint function', () => {
expect(request.value).toBe(value)
})
})

describe('getExternalUrl function', () => {
test('should return correct url for mint w/tokenId and referral', async () => {
const params = {
chainId: Chains.BASE,
contractAddress: getAddress('0x7e0b40af1d6f26f2141b90170c513e57b5edd74e'),
tokenId: 21,
referral: getAddress('0x1234567890123456789012345678901234567890'),
mmackz marked this conversation as resolved.
Show resolved Hide resolved
}
const result = await getExternalUrl(params)
expect(result).toBe(
'https://pods.media/mint-podcast/why-social-needs-a-layer-2-ft-ryan-li-of-cyber?referrer=0x1234567890123456789012345678901234567890',
)
})

test('should return correct url for mint w/tokenId and w/o referral', async () => {
const params = {
chainId: Chains.BASE,
contractAddress: getAddress('0x7e0b40af1d6f26f2141b90170c513e57b5edd74e'),
tokenId: 21,
}
const result = await getExternalUrl(params)
expect(result).toBe(
`https://pods.media/mint-podcast/why-social-needs-a-layer-2-ft-ryan-li-of-cyber?referrer=${ZORA_DEPLOYER_ADDRESS}`,
)
})

test('should return correct url for mint w/out tokenId', async () => {
const params = {
chainId: Chains.BASE,
contractAddress: getAddress('0x7e0b40af1d6f26f2141b90170c513e57b5edd74e'),
referral: getAddress('0x1234567890123456789012345678901234567890'),
}
const result = await getExternalUrl(params)
expect(result).toBe(
'https://pods.media/mint-podcast?referrer=0x1234567890123456789012345678901234567890',
)
})

test('should return fallback url if error occurs', async () => {
const params = {
chainId: Chains.BASE,
contractAddress: zeroAddress,
referral: getAddress('0x1234567890123456789012345678901234567890'),
}
const result = await getExternalUrl(params)
expect(result).toBe('https://pods.media')
})
})
35 changes: 34 additions & 1 deletion packages/pods/src/Pods.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import axios from 'axios'
import { FEES_ABI, ZORA_MINTER_ABI_1155 } from './abi'
import { CHAIN_ID_ARRAY } from './chain-ids'
import {
FIXED_PRICE_SALE_STRATS,
ZORA_DEPLOYER_ADDRESS,
} from './contract-addresses'
import { type AndArrayItem, getLatestTokenId } from './utils'
import { type AndArrayItem, getLatestTokenId, getUri } from './utils'
import {
type MintActionParams,
type TransactionFilter,
Expand Down Expand Up @@ -180,6 +181,38 @@ export const getFees = async (
}
}

export const getExternalUrl = async (
params: MintActionParams,
): Promise<string> => {
const { chainId, contractAddress, tokenId, referral } = params

try {
const client = createPublicClient({
chain: chainIdToViemChain(chainId),
transport: http(),
}) as PublicClient

const uri = await getUri(client, contractAddress, tokenId)
const cid = uri.split('/').slice(2).join('/')

const { data } = await axios.get(`https://arweave.net/${cid}`)

// different properties depending on uri function. One of these will be defined
const baseUrl = data.external_link ?? data.external_url

return `${baseUrl}?referrer=${referral ?? ZORA_DEPLOYER_ADDRESS}`
} catch (error) {
console.error('an error occurred fetching data from the contract')
if (error instanceof Error) {
console.error(error.message)
} else {
console.error(error)
}
// fallback to default pods url
return 'https://pods.media'
}
}

export const getSupportedTokenAddresses = async (
_chainId: number,
): Promise<Address[]> => {
Expand Down
5 changes: 4 additions & 1 deletion packages/pods/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import {
} from '@rabbitholegg/questdk-plugin-utils'

import {
getExternalUrl,
getFees,
getMintIntent,
getProjectFees,
getSupportedChainIds,
getSupportedTokenAddresses,
mint,
simulateMint,
} from './Pods.js'
} from './Pods'

export const Pods: IActionPlugin = {
pluginId: 'pods',
Expand All @@ -24,6 +25,8 @@ export const Pods: IActionPlugin = {
mint,
getProjectFees: async (params: ActionParams) =>
getProjectFees(params as unknown as MintActionParams),
getExternalUrl: async (params: ActionParams) =>
getExternalUrl(params as unknown as MintActionParams),
getFees: async (params: ActionParams) =>
getFees(params as unknown as MintActionParams),
getMintIntent,
Expand Down
37 changes: 37 additions & 0 deletions packages/pods/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,40 @@ export async function getLatestTokenId(
return 1
}
}

export async function getUri(
client: PublicClient,
contractAddress: Address,
tokenId?: number,
): Promise<string> {
if (tokenId == null) {
return (await client.readContract({
address: contractAddress,
abi: [
{
inputs: [],
name: 'contractURI',
outputs: [{ internalType: 'string', name: '', type: 'string' }],
stateMutability: 'view',
type: 'function',
},
],
functionName: 'contractURI',
})) as string
}

return (await client.readContract({
address: contractAddress,
abi: [
{
inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],
name: 'uri',
outputs: [{ internalType: 'string', name: '', type: 'string' }],
stateMutability: 'view',
type: 'function',
},
],
functionName: 'uri',
args: [BigInt(tokenId)],
})) as string
}
Loading