The nft-openaction-kit package simplifies the process of integrating an NFT minting open action into Lens applications. This package has two core functionalities:
When a user posts a link to an NFT in a Lens Publication, this package will parse data from the URL and smart contracts to embed an NFT minting open action into the Lens Publication.
When a post appears in a Lens application feed with the NFT minting action attached, the app can use this package to populate metadata to appear on a UI and generate calldata to perform the transaction.
What is suported
- Any NFT that is actively minting and is priced in ETH
What is not currently supported
- NFTs that are priced in other ERC20 tokens are not currently supported
- If an NFT page is listed as "secondary" this means it is no longer a primary mint and is not currently supported
- Any NFT that is actively minting
- Function 1:
detectAndReturnCalldata. Detects the NFT platform and returns the calldata to be used in the post action. - Function 2:
actionDataFromPost. Returns the encoded calldata from Decent and UI data for the post action. - Extensible: the kit is extensible to add new NFT platforms with the usage of
IPlatformServiceinterface. - Zora detection logic: detect collections with an active sale (ZoraCreatorFixedPriceSaleStrategy for ERC1155 or contract collection for ERC721). All other cases are discarded as they don't represent a minting event (require specific handling - e.g. Seaport integration).
actionDataFromPostis returingundefinedas the actionResponse from Decent is empty.
The route from Polygon to Zora is not configured in the Decent API.
-
Clone the repo
git clone https://github.com/0xnogo/nft-openAction-kit.git
-
Install NPM packages
yarn install
-
Build
yarn build
The package is not published. To use is locally, run
yarn linkin the root directory andyarn link nft-openaction-kitin the project you want to use it.
-
Create a .env file in the root directory and add the following variables:
DECENT_API_KEY=api-key
-
Instantiate the
NFTOpenActionKitclass and use thedetectAndReturnCalldataandactionDataFromPostmethods.
import { NftOpenActionKit } from "nft-openaction-kit";
// @param decentApiKey - string, required decent.xyz API key
// @param option fallbackRpcs - mapping of chainId to fallback RPC url
const nftOpenActionKit = new NftOpenActionKit({
decentApiKey: process.env.DECENT_API_KEY,
fallbackRpcs: {
[7777777]: `https://zora-mainnet.g.alchemy.com/v2/${process.env.VITE_ALCHEMY_API_KEY}`,
[8453]: `https://base-mainnet.g.alchemy.com/v2/${process.env.VITE_ALCHEMY_API_KEY}`,
[1]: `https://eth-mainnet.g.alchemy.com/v2/${process.env.VITE_ALCHEMY_API_KEY}`,
[10]: `https://opt-mainnet.g.alchemy.com/v2/${process.env.VITE_ALCHEMY_API_KEY}`,
[137]: `https://polygon-mainnet.g.alchemy.com/v2/${process.env.VITE_ALCHEMY_API_KEY}`,
[42161]: `https://arb-mainnet.g.alchemy.com/v2/${process.env.VITE_ALCHEMY_API_KEY}`,
},
});- When a Lens publication is created, the
detectAndReturnCalldatamethod can be used by passing a URL, it will be parsed and if a supported NFT link is found the response type is astringcontaining the open action calldata to be included within thepost,comment,quote, ormirrortransaction.
const fetchCalldata = async () => {
try {
const result = await nftOpenActionKit.detectAndReturnCalldata({
contentURI: url, // url string to parse NFT data from
publishingClientProfileId: "10", // profileId, the owner address of this profile receives frontend mint rewards
});
console.log(result || "No calldata found");
} catch (err) {
console.log(err);
}
};- Use
actionDataFromPostwhen a publicaiton is rendered on a Lens feed to generate the cross-chain transaction calldata to be included with theacttransaction.
const publication = {
profileId: "48935",
actionModules: ["0x99Cd5A6e51C85CCc63BeC61A177003A551953628"],
actionModulesInitDatas: [calldata],
pubId: "10",
};
try {
// Call the async function and pass the link
const result: ActionData = await nftOpenActionKit.actionDataFromPost({
post: publication,
profileId,
profileOwnerAddress,
senderAddress,
srcChainId,
quantity,
paymentToken,
executingClientProfileId,
mirrorerProfileId,
mirrorPubId,
sourceUrl,
});
} catch (error) {
console.log(error);
}The
actionDataFromPostfunction is accepting a subset of fields from Publication events (example event defined in https://github.com/wkantaros/lens-openAction).
The actionDataFromPost or generateUIData functions return a uiData property. This object contains NFT metadata that can be used on a frontend display. All available properties are detailed below:
type UIData = {
platformName: string;
platformLogoUrl: string;
nftName: string;
nftUri: string;
nftCreatorAddress?: string;
tokenStandard: string;
dstChainId: number;
rawMetadataUri?: string;
zoraAdditional?: ZoraAdditional;
podsAdditional?: PodsAdditional;
};
type ZoraAdditional = {
name?: string;
description?: string;
image?: string;
animation_url?: string; // video or audio field, if one exists
content?: {
mime?: string;
uri?: string;
};
};
export type PodsAdditional = {
animation_url?: string; // podcast audio file
artwork?: {
kind?: string;
type?: string;
uri?: string;
};
collection?: string;
credits?: {
name?: string;
role?: string;
}[];
description?: string;
episodeNumber?: number;
episodeTitle?: string;
external_url?: string;
image?: string;
name?: string;
podcast?: string;
primaryMedia?: {
kind?: string;
type?: string;
uri?: string;
duration?: number;
};
properties?: {
Collection?: string;
Podcast?: string;
guest_1?: Record<string, unknown>;
host_1?: Record<string, unknown>;
host_2?: Record<string, unknown>;
[key: string]: unknown;
};
publishedAt?: string;
version?: string;
};
- If an api is required, modify the SdkConfig type in
src/types/index.ts:
type SdkConfig = {
decentApiKey: string,
raribleApiKey?: string,
openSeaApiKey?: string,
};- Modify the initializePlatformConfig function in
src/DetectionEngine.tsand add the new platform config following the type:
type NFTPlatform = {
platformName: string,
platformLogoUrl: string,
urlPattern: RegExp,
urlExtractor: (url: string) => Promise<NFTExtraction | undefined>,
platformService: PlatformServiceConstructor,
};- Create a new file in
src/platformand add the platform service class. The class should implement theIPlatformServiceinterface.
export type NFTPlatform = {
platformName: string,
platformLogoUrl: string,
urlPattern: RegExp,
urlExtractor: (url: string) => Promise<NFTExtraction | undefined>,
platformService: PlatformServiceConstructor,
apiKey?: string,
};If an api key is required, make sure to add it in the
DetectionEngineclass and handle it in theinitializePlatformConfigfunction. The Rareble detection is an example of how to handle an api key.
- Create a new file in
src/platformand add the platform service class. The class should implement theIPlatformServiceinterface.
interface IPlatformService {
platformName: string;
getMinterAddress(
nftDetails: NFTExtraction,
mintSignature: string
): Promise<string>;
getMintSignature(
nftDetails: NFTExtraction,
ignoreValidSale?: boolean
): Promise<string | undefined>;
getUIData(
signature: string,
contract: string,
tokenId: bigint,
dstChainId: bigint,
sourceUrl?: string
): Promise<UIData | undefined>;
getPrice(
contractAddress: string,
nftId: bigint,
signature: string,
userAddress: string,
unit?: bigint,
sourceUrl?: string
): Promise<bigint | undefined>;
getArgs(
contractAddress: string,
tokenId: bigint,
senderAddress: string,
signature: string,
price: bigint,
quantity: bigint,
profileOwnerAddress: string,
sourceUrl?: string
): Promise<any[]>;
}