Home

Framework Quickstarts

Use Openfort with Node.js

Learn how to get started with Openfort and mint an asset with NodeJS.

What you'll learn:#

  • How to manage third-party dependencies using the npm or yarn package manager.
  • How to install the latest Openfort Node SDK.
  • How to send your first SDK request.
1

Set up a Openfort Node.js SDK

Open your project in the Openfort Dashboard.

The latest version of the Openfort Node.js server-side SDK supports Node.js versions 14+.

Terminal

_10
mkdir openfort-tutorial
_10
cd openfort-tutorial
_10
npm init -y
_10
npm install @openfort/openfort-node --save
_10
touch index.js

2

Declare Openfort Environment Variables

After your project is ready, grab your secret_key and public_key from the project.

Create a .env file and populate with your project's secret key.

Also make sure to add the package.json file.

.env

_10
YOUR_SECRET_KEY=sk_test_...

package.json

_16
{
_16
"name": "node",
_16
"version": "1.0.0",
_16
"description": "",
_16
"main": "index.js",
_16
"scripts": {
_16
"test": "echo \"Error: no test specified\" && exit 1",
_16
"dev": "node index.js"
_16
},
_16
"keywords": [],
_16
"author": "",
_16
"license": "ISC",
_16
"dependencies": {
_16
"@openfort/openfort-node": "^0.6.10"
_16
}
_16
}

3

Add a contract to Openfort

In this tutorial, we'll use a simple ERC-721 contract on the Polygon Amoy network deployed at 0x252...43A.

Once added, Openfort will return a contract id that you can use to interact with the contract. It starts with con_.

Terminal

_368
curl https://api.openfort.xyz/v1/contracts \
_368
-H "Authorization: Bearer $YOUR_SECRET_KEY" \
_368
-d chainId=80002 \
_368
-d address="0x2522F4Fc9aF2E1954a3D13f7a5B2683A00a4543A" \
_368
-d abi=[
_368
{
_368
"inputs": [],
_368
"stateMutability": "nonpayable",
_368
"type": "constructor"
_368
},
_368
{
_368
"anonymous": false,
_368
"inputs": [
_368
{
_368
"indexed": true,
_368
"internalType": "address",
_368
"name": "owner",
_368
"type": "address"
_368
},
_368
{
_368
"indexed": true,
_368
"internalType": "address",
_368
"name": "approved",
_368
"type": "address"
_368
},
_368
{
_368
"indexed": true,
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
}
_368
],
_368
"name": "Approval",
_368
"type": "event"
_368
},
_368
{
_368
"anonymous": false,
_368
"inputs": [
_368
{
_368
"indexed": true,
_368
"internalType": "address",
_368
"name": "owner",
_368
"type": "address"
_368
},
_368
{
_368
"indexed": true,
_368
"internalType": "address",
_368
"name": "operator",
_368
"type": "address"
_368
},
_368
{
_368
"indexed": false,
_368
"internalType": "bool",
_368
"name": "approved",
_368
"type": "bool"
_368
}
_368
],
_368
"name": "ApprovalForAll",
_368
"type": "event"
_368
},
_368
{
_368
"anonymous": false,
_368
"inputs": [
_368
{
_368
"indexed": true,
_368
"internalType": "address",
_368
"name": "from",
_368
"type": "address"
_368
},
_368
{
_368
"indexed": true,
_368
"internalType": "address",
_368
"name": "to",
_368
"type": "address"
_368
},
_368
{
_368
"indexed": true,
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
}
_368
],
_368
"name": "Transfer",
_368
"type": "event"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "address",
_368
"name": "to",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
}
_368
],
_368
"name": "approve",
_368
"outputs": [],
_368
"stateMutability": "nonpayable",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "address",
_368
"name": "owner",
_368
"type": "address"
_368
}
_368
],
_368
"name": "balanceOf",
_368
"outputs": [
_368
{
_368
"internalType": "uint256",
_368
"name": "",
_368
"type": "uint256"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
}
_368
],
_368
"name": "getApproved",
_368
"outputs": [
_368
{
_368
"internalType": "address",
_368
"name": "",
_368
"type": "address"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "address",
_368
"name": "owner",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "address",
_368
"name": "operator",
_368
"type": "address"
_368
}
_368
],
_368
"name": "isApprovedForAll",
_368
"outputs": [
_368
{
_368
"internalType": "bool",
_368
"name": "",
_368
"type": "bool"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "address",
_368
"name": "_to",
_368
"type": "address"
_368
}
_368
],
_368
"name": "mint",
_368
"outputs": [],
_368
"stateMutability": "nonpayable",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [],
_368
"name": "name",
_368
"outputs": [
_368
{
_368
"internalType": "string",
_368
"name": "",
_368
"type": "string"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
}
_368
],
_368
"name": "ownerOf",
_368
"outputs": [
_368
{
_368
"internalType": "address",
_368
"name": "",
_368
"type": "address"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "address",
_368
"name": "from",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "address",
_368
"name": "to",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
}
_368
],
_368
"name": "safeTransferFrom",
_368
"outputs": [],
_368
"stateMutability": "nonpayable",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "address",
_368
"name": "from",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "address",
_368
"name": "to",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
},
_368
{
_368
"internalType": "bytes",
_368
"name": "data",
_368
"type": "bytes"
_368
}
_368
],
_368
"name": "safeTransferFrom",
_368
"outputs": [],
_368
"stateMutability": "nonpayable",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "address",
_368
"name": "operator",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "bool",
_368
"name": "approved",
_368
"type": "bool"
_368
}
_368
],
_368
"name": "setApprovalForAll",
_368
"outputs": [],
_368
"stateMutability": "nonpayable",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "bytes4",
_368
"name": "interfaceId",
_368
"type": "bytes4"
_368
}
_368
],
_368
"name": "supportsInterface",
_368
"outputs": [
_368
{
_368
"internalType": "bool",
_368
"name": "",
_368
"type": "bool"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [],
_368
"name": "symbol",
_368
"outputs": [
_368
{
_368
"internalType": "string",
_368
"name": "",
_368
"type": "string"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [],
_368
"name": "tokenId",
_368
"outputs": [
_368
{
_368
"internalType": "uint256",
_368
"name": "",
_368
"type": "uint256"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
}
_368
],
_368
"name": "tokenURI",
_368
"outputs": [
_368
{
_368
"internalType": "string",
_368
"name": "",
_368
"type": "string"
_368
}
_368
],
_368
"stateMutability": "view",
_368
"type": "function"
_368
},
_368
{
_368
"inputs": [
_368
{
_368
"internalType": "address",
_368
"name": "from",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "address",
_368
"name": "to",
_368
"type": "address"
_368
},
_368
{
_368
"internalType": "uint256",
_368
"name": "tokenId",
_368
"type": "uint256"
_368
}
_368
],
_368
"name": "transferFrom",
_368
"outputs": [],
_368
"stateMutability": "nonpayable",
_368
"type": "function"
_368
}
_368
] \
_368
-d name="Simple NFT"

4

Prepare gas sponsorship

To offer gasless transaction (sponsor gas) in Openfort, your need to create a policy and a policy rule.

The policy rule will define the contract functions that you want to sponsor. In this example, we create a simple policy rule to pay for all user's interactions with the contract.

Grab your contract id and the policy id to include on your call.

Terminal

_10
curl https://api.openfort.xyz/v1/policies \
_10
-H "Authorization: Bearer $YOUR_SECRET_KEY" \
_10
-d chainId=80002 \
_10
-d name="simple sponsor" \
_10
-d "strategy[sponsorSchema]=pay_for_user"

Terminal

_10
curl https://api.openfort.xyz/v1/policies/:id/policy_rules \
_10
-H "Authorization: Bearer $YOUR_SECRET_KEY" \
_10
-d type="contract_functions" \
_10
-d functionName="All functions" \
_10
-d contract="con_..."

5

Mint an NFT

Now mint an NFT using the contract id and the player id that you created in the previous steps.

Openfort will encode the transaction based on the provided information in the interaction.

The smart account will be created and deployed automatically for you on the Amoy network.

Because optimistic is set to false, the response from creating the transactionIntents will contain a response.

Remember to replace the policy, contract and player ids with your own.

index.js

_33
const Openfort = require('@openfort/openfort-node').default;
_33
const openfort = new Openfort(process.env.YOUR_SECRET_KEY);
_33
_33
const main = async () => {
_33
_33
const player = await openfort.players.create({
_33
"name":"John Doe",
_33
"description":"Tutorial created account"
_33
});
_33
console.log("Success! Here is your player id: " + player.id);
_33
_33
const contractId = "con_...";
_33
const policyId = "pol_...";
_33
const chainId = 80002;
_33
const optimistic = false;
_33
const tokenId = '1' // Token ID to mint, should be unique
_33
const interaction_mint = {
_33
contract: contractId,
_33
functionName: "mint",
_33
functionArgs: [player.id, TokenId],
_33
};
_33
_33
const transactionIntent = await openfort.transactionIntents.create({
_33
"player":player.id,
_33
"chainId":chainId,
_33
"optimistic":optimistic,
_33
"interactions":[interaction_mint],
_33
"policy":policyId
_33
});
_33
console.log("Success! Here is your transactionIntent id: " + transactionIntent.id);
_33
_33
};
_33
main().then(() => process.exit(0));

6

Run the script

You're all set! Run the development server on your Terminal.

You can check the logs and events of the transaction intent in your dashboard.

Terminal

_10
npm run dev