Bridging steps:
- 1. Installing the library
- 2. Importing the dependencies
- 3. Getting the signer objects
- 4. Getting the Chain inner objects
- 5. Listing NFTs
- 6. Approving
- 7. Transferring NFTs between chains
- Minting NFTs(optional)
- Estimating the TX fee on the target chain (optional)
- ... and there's much more to come
Make sure nodejs is installed on your machine.
yarn add xp.network @elrondnetwork/erdjs ethers @taquito/taquito @temple-wallet/dappOR
npm i --save xp.network @elrondnetwork/erdjs ethers @taquito/taquito @temple-wallet/dappTo import the latest version of xp.network v.2.0 library:
yarn add "git+https://github.com/xp-network/xpjs#bleeding-edge" @elrondnetwork/erdjs ethers @taquito/taquito @temple-wallet/dappimport {
ChainFactoryConfigs,
ChainFactory,
Chain,
AppConfigs,
ChainParams,
} from "xp.network";
(async () => {
// Instantiate the chain factory for the
// Connecting to the mainnnets of all the blockchains:
const mainnetConfig = await ChainFactoryConfigs.MainNet();
const mainnetFactory: ChainFactory = ChainFactory(
AppConfigs.MainNet(),
mainnetConfig
);
// Connecting to the testnets of all the blockchains:
const testnetConfig = await ChainFactoryConfigs.TestNet();
const testnetFactory: ChainFactory = ChainFactory(
AppConfigs.TestNet(),
testnetConfig
);
// Switching between the mainnets & the testnets:
const factory: ChainFactory = mainnetFactory;
const CONFIG: Partial<ChainParams> = mainnetConfig;
})();Avoid using 3.1 setup in production. Use it for initial or backend testing only.
Add your private key to the environment:
touch .env
echo "SK=<Replace this with your Private Key>" >> .env// EVM chains compatible wallet:
import { Wallet } from "ethers";
import { config } from 'dotenv';
config();
// EVM signer for testing in the BE
const signer = new Wallet(
process.env.SK!,
// Replace 'polygonParams'
// with the relevant parameter
// from the table below
CONFIG.polygonParams?.provider
);| Chain | Parameters | Chain Nonce |
|---|---|---|
| Elrond | elrondParams | 2 |
| BSC | bscParams | 4 |
| Ethereum | ropstenParams | 5 |
| Avalanche | avalancheParams | 6 |
| Polygon | polygonParams | 7 |
| Fantom | fantomParams | 8 |
| Tron | tronParams | 9 |
| Harmony | harmonyParams | 12 |
| xDai | xDaiParams | 14 |
| Algorand | algorandParams | 15 |
| Fuse | fuseParams | 16 |
| Tezos | tezosParams | 18 |
| Velas | velasParams | 19 |
| Aurora | auroraParams | 21 |
| Godwoken | godwokenParams | 22 |
| Gatechain | gatechainParams | 23 |
| VeChain | vechainParams | 25 |
// EVM chains compatible signer:
import ethers from "ethers";
const signer = new ethers.providers.Web3Provider(window.ethereum).getSigner();// ELROND provider:
import { ExtensionProvider } from "@elrondnetwork/erdjs/out";
const elrondSigner = ExtensionProvider.getInstance();// Address is fetched from tronweb
(async () => {
const addresses = await window.tronLink.tronWeb.request({
method: "tron_requestAccounts",
});
const tronSigner = addresses[0];
})();import { typedAlgoSigner } from "xp.network/dist/helpers/algorand";
// Use the typedAlgoSigner function to get access to the Algorand signer
const algorandSigner = typedAlgoSigner();import { TempleWallet } from "@temple-wallet/dapp";
(async () => {
try {
const available = await TempleWallet.isAvailable();
if (!available) {
throw new Error("Temple Wallet is not installed");
}
const tezosSigner = new TempleWallet("bridge.xp.network");
} catch (error) {
console.error("Error:", error);
}
})();For the ways of connecting the wallets in the FE check-out our bridge repository
4. Getting the inner objects from this factory to be used for transferring, minting, and estimation of gas fees.
(async () => {
// Inner Object ================================ Chain Nonce
const bsc = await factory.inner(Chain.BSC); // 4
const ethereum = await factory.inner(Chain.ETHEREUM); // 5
const avax = await factory.inner(Chain.AVALANCHE); // 6
const polygon = await factory.inner(Chain.POLYGON); // 7
const fantom = await factory.inner(Chain.FANTOM); // 8
const harmony = await factory.inner(Chain.HARMONY); // 12
const gnosis = await factory.inner(Chain.XDAI); // 14
const fuse = await factory.inner(Chain.FUSE); // 16
const velas = await factory.inner(Chain.VELAS); // 19
const aurora = await factory.inner(Chain.AURORA); // 21
const godwoken = await factory.inner(Chain.GODWOKEN); // 22
const gatechain = await factory.inner(Chain.GATECHAIN); // 23
const vechain = await factory.inner(Chain.VECHAIN); // 25
// Non-EVM chains:
// Inner Object ================================ Chain Nonce
const elrond = await factory.inner(Chain.ELROND); // 2
const tron = await factory.inner(Chain.TRON); // 9
const algorand = await factory.inner(Chain.ALGORAND); // 15
const tezos = await factory.inner(Chain.TEZOS); // 18
})();This operation does not depend on a wallet since reading operations are free and, therefore, do not require signing.
(async () => {
// EVM:
const web3Nfts = await factory.nftList(
harmony, // The chain of interest
"0x...." // The public key of the NFT owner in a web3 chain
);
// Elrond:
const elrondNfts = await factory.nftList(
elrond, // The chain of interest
"erd1...." // The public key of the NFT owner in Elrond
);
// Tron:
const tronNfts = await factory.nftList(
tron, // The chain of interest
"TJuG..." // The public key of the NFT owner in Tron
);
// Algorand:
const algoNfts = factory.nftList(
algorand, // Algorand chain internal object
"PUPTH..." // The public key of the NFT owner in Algorand
);
// Tezos:
const tezosNfts = await factory.nftList(
tezos, // Tezos chain internal object
"tz1..." // The public key of the NFT owner in Tezos
);
})();// Choosing an NFT to transfer:
const web3ChosenOne = web3Nfts[0];
const elrondChosenOne = elrondNfts[0];
const tronChosenOne = tronNfts[0];
const algoChosenOne = algoNfts[0];
const tezosChosenOne = tezosNfts[0];
// Checking the selected NFT object
console.log("EVM Selected NFT: ", web3ChosenOne);
console.log("Elrond Selected NFT: ", elrondChosenOne);
console.log("Tron Selected NFT: ", tronChosenOne);
console.log("Algorand Selected NFT: ", algoChosenOne);
console.log("Tezos Selected NFT: ", tezosChosenOne);{
"boosterId": 10000000788939,
"id": "10002366816",
"txHash": "0x37c9b7c54ac05d5e00dd5cff06722fb67bed91ec91732875071f74bce8752e41",
"randomNumber": "0x1459a03e3d7a5510023e7385d438508d725dd19de2237c6c1d79a9883b6dc0b3",
"image": "https://assets.polkamon.com/images/Unimons_T02C03H06B04G00.jpg",
"external_url": "https://polkamon.com/polkamon/T02C03H06B04G00",
"description": "The Unifairy are the most magical and fairest of Polkamon. Their wings stretch into the realms beyond this world, enchanting those around her by her unique disposition.",
"name": "Unifairy",
"initialProbabilities": {
"horn": 0.2,
"color": 0.25,
"background": 1,
"glitter": 0.99,
"type": 0.135
},
"attributes": [
{
"trait_type": "Type",
"value": "Unifairy"
},
{
"trait_type": "Horn",
"value": "Spiral Horn"
},
{
"trait_type": "Color",
"value": "Blue"
},
{
"trait_type": "Background",
"value": "Mountain Range"
},
{
"trait_type": "Opening Network",
"value": "Binance Smart Chain"
},
{
"trait_type": "Glitter",
"value": "No"
},
{
"trait_type": "Special",
"value": "No"
},
{
"display_type": "date",
"trait_type": "Birthday",
"value": 1633650473
},
{
"display_type": "number",
"trait_type": "Booster",
"value": 10000000788939
}
],
"opening_network": "Binance Smart Chain",
"background_color": "FFFFFF",
"animation_url": "https://assets.polkamon.com/videos/Unimons_T02C03H06B04G00.mp4",
"code": "T02C03H06B04G00",
"uri": "https://meta.polkamon.com/meta?id=10002366816",
"native": {
"chainId": "4",
"tokenId": "10002366816",
"owner": "0x0d7df42014064a163DfDA404253fa9f6883b9187",
"contract": "0x85f0e02cb992aa1f9f47112f815f519ef1a59e2d",
"symbol": "PMONC",
"name": "PolkamonOfficialCollection",
"uri": "https://meta.polkamon.com/meta?id=10002366816",
"contractType": "ERC721"
}
}{
"name": "DRVR NOT LVR",
"description": "Cliff Blank | Community Pool Drop\n\nWe would need a license to love, there would be fewer lines, fewer misunderstandings but definitely more accidents. \nThe arteries of our heart would be 4 lanes so that we could reach love in a short time. Of course, there could always be works and exits closed but at least we would have fewer surprises and we would react accordingly, choosing another exit or deciding to continue on our way.",
"decimals": 0,
"isBooleanAmount": true,
"image": "https://ipfs.infura.io/ipfs/QmX4n4QJBsGmVuszy1fXMJHpGnpkp9BePVJNQ8Lf18yA8z",
"artifactUri": "https://ipfs.infura.io/ipfs/QmX4n4QJBsGmVuszy1fXMJHpGnpkp9BePVJNQ8Lf18yA8z",
"wrapped": {
"contract": "0x1BFb3FbCf1ce331B7AAE03a3c0Bf3AcF685F4bD6",
"tokenId": "10",
"contractType": 721,
"origin": "14",
"original_uri": "https://ipfs.infura.io/ipfs/QmdtemgadGPgWSn9Lq1RvQn4Q2ofEpRNr7ox8oMyNWJ9ma",
"mint_with": "0x3a1d5a87c5f0c2f5c5e079b0f234d8797ee0e9b4",
"source_mint_ident": "0x1BFb3FbCf1ce331B7AAE03a3c0Bf3AcF685F4bD6"
},
"attributes": [
{
"trait_type": "Original Chain",
"value": "xDai"
},
{
"trait_type": "Original Chain Nonce",
"value": "14"
},
{
"trait_type": "Original URI",
"value": "https://ipfs.infura.io/ipfs/QmdtemgadGPgWSn9Lq1RvQn4Q2ofEpRNr7ox8oMyNWJ9ma"
}
],
"displayUri": "https://ipfs.infura.io/ipfs/QmX4n4QJBsGmVuszy1fXMJHpGnpkp9BePVJNQ8Lf18yA8z",
"thumbnailUri": "https://ipfs.infura.io/ipfs/QmX4n4QJBsGmVuszy1fXMJHpGnpkp9BePVJNQ8Lf18yA8z",
"ipfs": false
}(async () => {
// EVM example
const isApprovedEVM = await harmony.approveForMinter(web3ChosenOne, signer);
console.log("Is Approved in an EVM:", isApprovedEVM);
// Elrond example
const isApprovedElrond = await elrond.approveForMinter(
elrondChosenOne,
elrondSigner
);
console.log("Is Approved in Elrond:", isApprovedElrond);
// Tron example
const isApprovedTron = await elrond.approveForMinter(
tronChosenOne,
tronSigner
);
console.log("Is Approved in Tron:", isApprovedTron);
// Algorand example
const isApprovedAlgorand = await algorand.approveForMinter(
algoChosenOne,
algorandSigner
);
console.log("Is Approved in Algorand:", isApprovedAlgorand);
// Tezos example
const isApprovedTezos = await algorand.approveForMinter(
tezosChosenOne,
tezosSigner
);
console.log("Is Approved in Tezos:", isApprovedTezos);
})();(async () => {
// EVM compatible chains example:
const web3Result = await factory.transferNft(
harmony, // The Source Chain.
bsc, // The Destination Chain.
theChosenOne, // The NFT object you have chosen from the list.
signer, // The web3 signer object (see p. 3.2 above).
"ADDRESS OF THE RECEIVER" // The address whom you are transferring the NFT to.
);
console.log(web3Result);
// Elrond example:
const elrondResult = await factory.transferNft(
elrond, // The Source Chain.
tron, // The Destination Chain.
elrondChosenOne, // The NFT object you have chosen from the list.
elrondSigner, // The Elrond signer object (see p. 3.3 above).
"ADDRESS OF THE RECEIVER" // The address whom you are transferring the NFT to.
);
console.log(elrondResult);
// Tron example:
const tronResult = await factory.transferNft(
tron, // The Source Chain.
elrond, // The Destination Chain.
tronChosenOne, // The NFT object you have chosen from the list.
tronSigner, // The Tron signer object (see p. 3.4 above).
"ADDRESS OF THE RECEIVER" // The address whom you are transferring the NFT to.
);
console.log(tronResult);
// Algorand example:
const algorandResult = await factory.transferNft(
algorand, // The Source Chain.
elrond, // The Destination Chain.
algoChosenOne, // The NFT object you have chosen from the list.
algorandSigner, // The Tron signer object (see p. 3.5 above).
"ADDRESS OF THE RECEIVER" // The address whom you are transferring the NFT to.
);
console.log(algorandResult);
// Tezos example:
const tezosResult = await factory.transferNft(
tezos, // The Source Chain.
velas, // The Destination Chain.
algoChosenOne, // Or the NFT object you have chosen from the list.
algorandSigner, // The Tron signer object (see p. 3.5 above).
"ADDRESS OF THE RECEIVER" // The address whom you are transferring the NFT to.
);
console.log(tezosResult);
})();- Just call the mint function on the factory with suitable arguments.
- For Web3 Chains:
(async () => {
// Web3Provider generally refers to a walletProvider like Metamask.
const receipt = await factory.mint(
avax, // The chain where to mint
signer, // The browser injected signer
{
// Could be an IPFS URL or Any URL that points to a Metadata
uris: [metadata.url],
// Description of your NFT. Can be an object.
attrs: description,
// A name that defines your NFT.
name: name,
// The contract with which you want to mint the NFT.
contract: "Can be fetched from the mainnetConfig or testnetConfig",
}
);
})();- For Elrond:
(async () => {
const receipt = await factory.mint(
elrond, // The chain where to mint
elrondSigner, // The browser injected signer
{
// Could be an IPFS URL or Any URL that points to a Metadata
uris: [metadata.url],
// Description of your NFT. Can be an object.
attrs: description,
// A name that defines your NFT.
name: name,
// The identifier with which you want to mint the NFT. You have to own this identifier. i.e.
identifier: "XPNFT-eda5d0-c5",
}
);
})();- For Tron:
const receipt = await factory.mint(avax, tronSigner, {
// Could be an IPFS URL or Any URL that points to a Metadata
uris: [metadata.url],
// Description of your NFT. Can be an object.
attrs: description,
// A name that defines your NFT.
name: name,
// The contract with which you want to mint the NFT.
contract: "Can be fetched from the mainnetConfig or testnetConfig",
});P.S. The library is a work in progress. More features will be added soon.
(async () => {
const feeEstimation = await factory.estimateFees(
algorand, // The Source Chain.
tezos, // The Destination Chain.
algoChosenOne, // The NFT object you have chosen from the list.
"tz1..." // The public key of the NFT owner in Tezos
);
console.log(`The estimated fee on Tezos is: ${feeEstimation} Algos`);
})();- In case you're using the library in a console application and getting errors, go to:
- node_modules/xpnet-nft-list/dist/nft-list/model/moralis/MoralisNftListService.js
Now your line #7 looks like this (to be used in the FE):
7 const moralis_1 = __importDefault(require("moralis"));Change it like so (for BE usage):
7 const moralis_1 = __importDefault(require("moralis/node"));