Bridging steps:
- 1. Installing the library
- 2. Importing the dependencies
- 3. Getting the signer objects
- 4. Getting the Chain's 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 much more to come
Make sure node.js is installed on your machine.
yarn add xp.networkOR
npm i --save xp.networkTo import the latest version of the xp.network library:
yarn add "git+https://github.com/xp-network/xpjs#bleeding-edge"import{ChainFactoryConfigs,ChainFactory,Chain,AppConfigs,ChainParams,import{config}from'dotenv';config();}from"xp.network";(async()=>{// Instantiate the chain factory for the// Connecting to the mainnnets of all the blockchains:constmainnetConfig=awaitChainFactoryConfigs.MainNet();constmainnetFactory: ChainFactory=ChainFactory(AppConfigs.MainNet(),mainnetConfig);// Connecting to the testnets of all the blockchains:consttestnetConfig=awaitChainFactoryConfigs.TestNet();consttestnetFactory: ChainFactory=ChainFactory(AppConfigs.TestNet(),testnetConfig);// Switching between the mainnets & the testnets:constfactory: ChainFactory=mainnetFactory;// or = testnetConfig;constCONFIG: Partial<ChainParams> = mainnetConfig; // or = testnetConfig;
})();Avoid using the
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 BEconstsigner=newWallet(process.env.SK!,// Replace 'polygonParams'// with the relevant parameter// from the table belowCONFIG.polygonParams?.provider);// EVM chains compatible signer:importethersfrom"ethers";constsigner=newethers.providers.Web3Provider(window.ethereum).getSigner();// MetaversX provider (injected from the browser extension):import{ExtensionProvider}from"@metaversxnetwork/erdjs/out";constmetaversxSigner=ExtensionProvider.getInstance();// MetaversX signer from a PEM key stored in the .env fileimport{UserSigner}from"@metaversxnetwork/erdjs/out";constmetaversxSigner=UserSigner.fromPem(process.env.ELROND_PEM!);// Address is fetched from tronweb(async()=>{constaddresses=awaitwindow.tronLink.tronWeb.request({method: "tron_requestAccounts",});consttronSigner=addresses[0];})();import{typedAlgoSigner}from"xp.network/dist/helpers/algorand";// Use the typedAlgoSigner function to get access to the Algorand signerconstalgorandSigner=typedAlgoSigner();import{TempleWallet}from"@temple-wallet/dapp";(async()=>{try{constavailable=awaitTempleWallet.isAvailable();if(!available){thrownewError("Temple Wallet is not installed");}consttezosSigner=newTempleWallet("bridge.xp.network");}catch(error){console.error("Error:",error);}})();import{SecretNetworkClient,Wallet}from"secretjs";import{SecretNftInfo}from"xp.network/dist/helpers/secret";constwallet=newWallet(process.env.mnemonic!);// Testnet exampleconstclient=awaitSecretNetworkClient.create({chainId: "pulsar-2",grpcWebUrl: TestNetRpcUri.SECRET,wallet: wallet,walletAddress: wallet.address,});import{config}from"dotenv";config();import{AppConfigs,Chain,ChainFactory,ChainFactoryConfigs,}from"xp.network";import{mnemonicToKeyPair}from"tonweb-mnemonic";(async()=>{constfactory=ChainFactory(AppConfigs.TestNet(),awaitChainFactoryConfigs.TestNet());constton=awaitfactory.inner(Chain.TON);consttonSigner=ton.tonKpWrapper(// where TON_MNEMONIC="space separated mnemonic phrase ..."awaitmnemonicToKeyPair(process.env.TON_MNEMONIC!.split()));})();import{connect,InMemorySigner,KeyPair,keyStores}from"near-api-js";import{config}from"dotenv";config();// Retrieving the Private Key from environmentconst{SK}=process.env;constkeyStore=newkeyStores.InMemoryKeyStore();constkeyPair=KeyPair.fromString(`ed25519:${SK}`);keyStore.setKey(network,account,keyPair);constsigner=newInMemorySigner(keyStore);constprovider=awaitconnect({headers: {},nodeUrl: TestNetRpcUri.NEAR,networkId: network,
signer,});import{config}from"dotenv";import{Connection,Keypair}from"@solana/web3.js";import{Metaplex,keypairIdentity}from"@metaplex-foundation/js";config();// Extracting the variables from .envconst{URL,SK}=process.env;// Solana providerconstprovider=newConnection(URL!);// Convert secret key (SK) to Uint8Arrayconstbuffer=require("bs58").decode(SK!);constkeyAsArray=newUint8Array(buffer.buffer,buffer.byteOffset,buffer.byteLength/Uint8Array.BYTES_PER_ELEMENT);// Solana signerconstpayer=Keypair.fromSecretKey(keyAsArray);// Metaplex Solana token standardconstmetaplex=Metaplex.make(provider).use(keypairIdentity(payer));// Client for interacting with NFT contractsconstnftc=metaplex.nfts();import{hethers,Wallet}from"@hashgraph/hethers";import{config}from"dotenv";config();consttestnetProvider=hethers.getDefaultProvider("testnet");constmainnetProvider=hethers.getDefaultProvider("mainnet");consthederaSigner=newWallet({privateKey: process.env.SK!,account: process.env.PK!,isED25519Type: true,}asany,mainnetProvider);For the ways of connecting the wallets in the FE check-out our bridge repository
| Chain | Parameters | Chain Nonce |
|---|---|---|
| MetaversX | metaversxParams | 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 |
| Solana | solanaParams | 26 |
| TON | tonParams | 27 |
| DFinity | dfinityParams | 28 |
| Hedera | hederaParams | 29 |
| Skale | skaleParams | 30 |
| NEAR | nearParams | 31 |
| Moonbeam | moonbeamParams | 32 |
| Abeychain | abeychainParams | 33 |
| Aptos | aptosParams | 34 |
| Caduceus | caduceusParams | 35 |
| OKC | okcParams | 36 |
| Arbitrum Nova | arbitrumParams | 37 |
| Bitgert | bitgertParams | 38 |
4. Getting the inner objects from this factory to be used for transferring, minting, and estimation of gas fees.
(async()=>{// EVM compatible chains:// Inner Object ====================================== Chain Nonceconstbsc=awaitfactory.inner(Chain.BSC);// 4constethereum=awaitfactory.inner(Chain.ETHEREUM);// 5constavax=awaitfactory.inner(Chain.AVALANCHE);// 6constpolygon=awaitfactory.inner(Chain.POLYGON);// 7constfantom=awaitfactory.inner(Chain.FANTOM);// 8constharmony=awaitfactory.inner(Chain.HARMONY);// 12constgnosis=awaitfactory.inner(Chain.XDAI);// 14constfuse=awaitfactory.inner(Chain.FUSE);// 16constvelas=awaitfactory.inner(Chain.VELAS);// 19constaurora=awaitfactory.inner(Chain.AURORA);// 21constgodwoken=awaitfactory.inner(Chain.GODWOKEN);// 22constgatechain=awaitfactory.inner(Chain.GATECHAIN);// 23constvechain=awaitfactory.inner(Chain.VECHAIN);// 25consthedera=awaitfactory.inner(Chain.HEDERA);// 29constskale=awaitfactory.inner(Chain.SKALE);// 30constmoonbeam=awaitfactory.inner(Chain.MOONBEAM);// 32constabeychain=awaitfactory.inner(Chain.ABEYCHAIN);// 33constcauseus=awaitfactory.inner(Chain.CADUCEUS);//35constokc=awaitfactory.inner(Chain.OKC);//36constarbitrum=awaitfactory.inner(Chain.ARBITRUM);//37constbitgert=awaitfactory.inner(Chain.BITGERT);//38// Non-EVM chains:// Inner Object ====================================== Chain Nonceconstmetaversx=awaitfactory.inner(Chain.ELROND);// 2consttron=awaitfactory.inner(Chain.TRON);// 9constalgorand=awaitfactory.inner(Chain.ALGORAND);// 15consttezos=awaitfactory.inner(Chain.TEZOS);// 18constsecret=awaitfactory.inner(Chain.SECRET);// 24constsolana=awaitfactory.inner(Chain.SOLANA);// 26constton=awaitfactory.inner(Chain.TON);// 27constdfinity=awaitfactory.inner(Chain.DFINITY);// 28constnear=awaitfactory.inner(Chain.NEAR);// 31constaptos=awaitfactory.inner(Chain.APTOS);//34})();This operation does not depend on a wallet since reading operations are free and, therefore, do not require signing.
(async()=>{// EVM:constweb3Nfts=awaitfactory.nftList(harmony,// The chain of interest"0x...."// The public key of the NFT owner in a web3 chain);// MetaversX:constmetaversxNfts=awaitfactory.nftList(metaversx,// The chain of interest"erd1...."// The public key of the NFT owner in MetaversX);// Tron:consttronNfts=awaitfactory.nftList(tron,// The chain of interest"TJuG..."// The public key of the NFT owner in Tron);// Algorand:constalgoNfts=factory.nftList(algorand,// Algorand chain internal object"PUPTH..."// The public key of the NFT owner in Algorand);// Tezos:consttezosNfts=awaitfactory.nftList(tezos,// Tezos chain internal object"EQB..."// The public key of the NFT owner in Tezos);// Secret:constsecretNfts=awaitfactory.nftList(secret,// Secret chain internal object"secret1..."// The public key of the NFT owner in Secret);// TON:consttonNfts=awaitfactory.nftList(ton,// TON chain internal object"tz1..."// The public key of the NFT owner in TON);// NEARconstnearNFTs=awaitnear.nftList(//@ts-ignoreawaitprovider.account("near-account-here"),"contract-address");// Hedera:consthederaNFTs=awaitfactory.nftList(hedera,"0.0.xxxxxxx"// Hedera / EVM address);})();// Choosing an NFT to transfer:constweb3ChosenOne=web3Nfts[0];constmetaversxChosenOne=metaversxNfts[0];consttronChosenOne=tronNfts[0];constalgoChosenOne=algoNfts[0];consttezosChosenOne=tezosNfts[0];constsecretChosenOne=secretNfts[0];consttonChosenOne=tonNfts[0];constnearChosenOne=nearNFTs[0];consthederaChosenOne=hederaNFTs[0];// Checking the selected NFT objectconsole.log("EVM Selected NFT: ",web3ChosenOne);console.log("MetaversX Selected NFT: ",metaversxChosenOne);console.log("Tron Selected NFT: ",tronChosenOne);console.log("Algorand Selected NFT: ",algoChosenOne);console.log("Tezos Selected NFT: ",tezosChosenOne);console.log("Secret Selected NFT: ",secretChosenOne);console.log("Ton Selected NFT: ",tonChosenOne);console.log("NEAR Selected NFT: ",nearChosenOne);console.log("Hedera Selected NFT: ",hederaChosenOne);{
"uri": "https://api.alturanft.com/meta/chain-caders/",
"native": {
"chainId": "4", // ChainId (4 = BSC)"tokenId": "2639", // ID in the NFT smart contract"contract": "0x387d38eEaaa7F1235c00aE6ee9b1462c026007f4",
"owner": "0x6449b68cc5675f6011e8DB681B142773A3157cb9",
"uri": "https://api.alturanft.com/meta/chain-caders/",
"symbol": null,
"name": "ChainCaders", // Collection Name"contractType": "ERC1155"
},
"collectionIdent": "0x387d38eeaaa7f1235c00ae6ee9b1462c026007f4"
}{
"uri": "https://nft.xp.network/w/30576349324667796398547334318",
"native": {
"chainId": "4", // Original chainId"tokenId": "30576349324667796398547334318", // Wrapped ID"contract": "0x8Ae5Fa4DDb131695CDe906BE03b33ebb277DF9A4", // Original Owner"owner": "0x6449b68cc5675f6011e8DB681B142773A3157cb9",
"uri": "https://nft.xp.network/w/30576349324667796398547334318", // Original URI"symbol": "vr3DNFTs", // Custom collection name"name": "Virtual Reality 3D NFTs", // Custom collection name"contractType": "ERC721"
},
"collectionIdent": "0x8ae5fa4ddb131695cde906be03b33ebb277df9a4"
}(async()=>{// EVM exampleconstisApprovedEVM=awaitharmony.approveForMinter(web3ChosenOne,signer);console.log("Is Approved in an EVM:",isApprovedEVM);// MetaversX exampleconstisApprovedMetaversX=awaitmetaversx.approveForMinter(metaversxChosenOne,metaversxSigner);console.log("Is Approved in MetaversX:",isApprovedMetaversX);// Tron exampleconstisApprovedTron=awaitmetaversx.approveForMinter(tronChosenOne,tronSigner);console.log("Is Approved in Tron:",isApprovedTron);// Algorand exampleconstisApprovedAlgorand=awaitalgorand.approveForMinter(algoChosenOne,algorandSigner);console.log("Is Approved in Algorand:",isApprovedAlgorand);// Tezos exampleconstisApprovedTezos=awaitalgorand.approveForMinter(tezosChosenOne,tezosSigner);console.log("Is Approved in Tezos:",isApprovedTezos);// Secret exampleconstsecretApprove=awaitscrt.preTransfer(client,chosenOne,newBigNumber(0));console.log("Approved for Secret:",secretApprove);// TON// Approval is not required in TON...// NEARconstnearApproved=near.preTransfer(sender,chosenOne,0/*_fee, can be 0 here*/,{
receiver,
to,});})();(async()=>{// EVM compatible chains example:constweb3Result=awaitfactory.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);// MetaversX example:constmetaversxResult=awaitfactory.transferNft(metaversx,// The Source Chain.tron,// The Destination Chain.metaversxChosenOne,// The NFT object you have chosen from the list.metaversxSigner,// The MetaversX signer object (see p. 3.3 above)."ADDRESS OF THE RECEIVER"// The address whom you are transferring the NFT to.);console.log(metaversxResult);// Tron example:consttronResult=awaitfactory.transferNft(tron,// The Source Chain.metaversx,// 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:constalgorandResult=awaitfactory.transferNft(algorand,// The Source Chain.metaversx,// 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:consttezosResult=awaitfactory.transferNft(tezos,// The Source Chain.velas,// The Destination Chain.tezosChosenOne,// Or the NFT object you have chosen from the list.tezosrandSigner,// 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);// TON example:consttonResult=awaitfactory.transferNft(ton,// The Source Chain.abeychain,// The Destination Chain.tonChosenOne,// Or the NFT object you have chosen from the list.tonSigner,// The Tron signer object (see p. 3.5 above)."ADDRESS OF THE RECEIVER"// The address whom you are transferring the NFT to.);console.log(tonResult);// NEAR example:constneraResult=awaitfactory.transferNft(near,bsc,nearChosenOne,//@ts-ignoreawaitprovider.account("near-account"),"ADDRESS OF THE RECEIVER"// The address whom you are transferring);// Hedera exampleconsthederaResult=awaitfactory.transferNft(hedera,moonbeam,hederaChosenOne,hederaSigner,"ADDRESS OF THE RECEIVER"// The address whom you are transferring the NFT to.);})();- Just call the mint function on the factory with suitable arguments.
- For Web3 Chains:
(async()=>{// Web3Provider generally refers to a walletProvider like Metamask.constreceipt=awaitfactory.mint(avax,// The chain where to mintsigner,// The browser injected signer{// Could be an IPFS URL or Any URL that points to a Metadatauris: [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 MetaversX:
(async()=>{// Deploying ESDTs:constresponse=awaitmetaversx.issueESDTNft(metaversxSigner,"Target","TGT",true,// canFreezetrue,// canWipetrue// canTransferNftCreateRole);// Checking whether ESDTs exist for this accountconstesdts=awaitmetaversx.mintableEsdts(metaversxSigner.getAddress()).catch((e)=>{console.log("Failed to get Mintable ESDTs",e)returnundefined})constidentifier=esdts ? esdts[0]: undefined;if(!identifier){thrownewError("No ESDT found for this address");}// Minting an NFT to an ESDTconstresponse=awaitmetaversx.mintNft(metaversxSigner,{
identifier,// Your ESDT tokenquantity: 1,// How many tokens you want to mint > 0name: "Your token name goes here",uris: ["replace with your link(s)"],}asany);console.log(response)})();- For Tron:
constreceipt=awaitfactory.mint(avax,tronSigner,{// Could be an IPFS URL or Any URL that points to a Metadatauris: [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()=>{constfeeEstimation=awaitfactory.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`);})();To implement v3 transfers for chain:
- Specify v3_chainId for the chain in src/consts.ts
- Specify v3_bridge contract address for the chain params in src/factory/factories.ts
- Implement getTokenInfo, getClaimData, lockNFT, claimV3NFT methods for the chain helper (see examples - src/helpers/elrond/elrond.ts, src/helpers/evm/web3.ts)
- In order to allow UI to identify NFT origin chain implement getNftOrigin for the chain helper