Easy Wrap and Unwrap

Building with ITEMs ensures total interoperability with every Token and dApp that exists on the Ethereum Network. Using the ETHITEM standard methodology, you can build any kind of dApp to interact with ITEMs by wrapping and unwrapping user funds in the background. You just need to add these calls into your Contracts:

Wrap ERC20

//Get my favorite ERC20 address
var myFavoriteERC20Token = new web3.eth.Contract(configuration.ERC20ABI, configuration.myFavoriteERC20Address);

//Get the amount to wrap, expressed in decimals.
var myFavoriteERC20AmountToWrap = configuration.myFavoriteERC20AmountToWrap;

//Call the Orchestrator and then the KnowledgeBase to retrieve the last ERC20Wrapper ITEM
var knowledgeBase = new web3.eth.Contract(configuration.EthItemKnowledgeBaseABI , await ethItemOrchestrator.knowledgeBase().call());
var collectionAddress = await knowledgeBase.methods.erc20Wrapper().call();

//Normalize the address for eventual search by address purposes
collectionAddress = web3.utils.toChecksumAddress(collectionAddress);

//Collection category to distinguish all collection types, "W20" means that this Collection is a Wrapper of ERC20 Tokens
var collectionCategory = "W20";

var collectionABI = configuration.W20ABI;

//The needed basic info to operate are of course the Collection address, category and Smart Contract. They can be of course enriched
var collection = {
    address : collectionAddress,
    category : collectionCategory,
    contract : new web3.eth.Contract(collectionABI, collectionAddress)
};

//First of all, you need to approve the funds transfer by the Collection
await myFavoriteERC20Token.methods.approve(collection.address, myFavoriteERC20AmountToWrap).send();

//Now you can call the Collection to wrap tokens.
//ERC20Wrapper exposes the method
//function mint(address erc20TokenAddress, uint256 amount) external returns (uint256 objectId, address wrapperAddress);
//To let you wrap your tokens
await collection.contract.methods['mint(address,uint256)'](myFavoriteERC20Token.options.address, myFavoriteERC20AmountToWrap).send();

//Now that you minted your tokens, you can easily retrieve the objectId corresponding to the ERC20 Token address you used
//ERC20Wrapper exposed the method
//function object(address erc20TokenAddress) external view returns (uint256 objectId);
//To retrieve the objectId you need.
var objectId = await collection.contract.methods.object(myFavoriteERC20Token.options.address).call();

//There will always be a unique objectId for every wrapped ERC20 Token contract. It is created the first time someone mints tokens of that ERC20

//Now you can use that objectId to interact with your balance tokens, e.g. you can retrieve your balance
var myBalanceInCollection = await collection.contract.methods.balanceOf(web3.eth.accounts[0], objecId).call();

//And transfer it to another account
await collection.contract.methods.safeTransferFrom(web3.eth.accounts[0], configuration.receiverAccountAddress, objectId, myBalanceInCollection, "0x").send();

//If you want to wrap some ETH, you need to use the mintETH() function
await collection.contract.methods.mintETH().send({ from: web3.eth.accounts[0], gas: configuration.transactionHash, value: configuration.ETHAmountToWrap});

//The objectId representing ETH can be easily grabbed using the ETHEREUM_OBJECT_ID function
var ethereumObjectId = await collection.contract.methods.ETHEREUM_OBJECT_ID().call();

//Now you can use that objectId to interact with your balance tokens, e.g. you can retrieve your balance
var myEthBalanceInCollection = await collection.contract.methods.balanceOf(web3.eth.accounts[0], ethereumObjectId).call();

//And transfer it to another account
await collection.contract.methods.safeTransferFrom(web3.eth.accounts[0], configuration.receiverAccountAddress, myEthBalanceInCollection, myEthBalanceInCollection, "0x").send();                    

Wrap ERC1155

//Get my favorite ERC1155 address
var myFavoriteERC1155Token = new web3.eth.Contract(configuration.ERC1155ABI, configuration.myFavoriteERC1155Address);

//Get the objectId to wrap
var objectId = configuration.myFavoriteERC1155ObjectToWrap;

//Get the amount to wrap
var myFavoriteERC1155AmountToWrap = configuration.myFavoriteERC1155AmountToWrap;

//ERC1155 Tokens can be wrapped in two ways: transferring original NFTs to wrap to Orchestrator or directly to the previously created Wrapper.
//The second way helps to save gas, but can be of course used only if someone has previously wrapped some NFTs of the desired Token.
//So let's start defining the Orchestrator as the default receiver, then try to replace it retrieving the Wrapper, if any.

var nftReceiver = ethItemOrchestrator.options.address;

//For computation operations
var voidEthereumAddress = "0x0000000000000000000000000000000000000000";

//Encapsulate the logic inside a function so we are able to re-use it in future
var retrieveLatestWrapperAddress = async function retrieveLatestWrapperAddress(tokenAddress) {

    //It is always recommended to wrap a token using the latest version of the corresponding model.
    //This info is in the active Factory referenced by the Orchestrator
    var factoryAddress = await ethItemOrchestrator.methods.factory().call();
    var factory = new web3.eth.Contract(configuration.EthItemFactoryABI, factoryAddress);

    //Position 0 is model address, position 1 is model version
    var modelVersion = (await factory.methods.erc1155WrapperModel())[1];

    //The EthItem Knowledge Bases, referenced by the Orchestrator, contain all previously wrapped Tokens
    var knowledgeBasesAddresses = await ethItemOrchestrator.methods.knowledgeBases().call();

    //We don't know where the wrapper is located, so we need to search in all existing knowledge bases
    //Knowledge Base has an extremely simple logic, so it shouldn't change frequently and the list stays short
    for(var knowledgeBaseAddress of knowledgeBasesAddresses) {
        var knowledgeBase = new web3.eth.Contract(configuration.EthItemKnowledgeBaseABI, knowledgeBaseAddress);
        var wrapperAddress = await knowledgeBase.methods.wrapper(tokenAddress, modelVersion);
        //If the result is different from address(0), then we found our guy
        if(wrapperAddress !== voidEthereumAddress) {
            return wrapperAddress;
        }
    }
    //Found nothing, returns address(0)
    return voidEthereumAddress;
};

//Use the previously written logic
var wAddr = await retrieveLatestWrapperAddress(myFavoriteERC1155Token.options.address);

//If the computation returns an already-created Wrapper, we can save more gas bypassing the Orchestrator as a receiver
if(wAddr !== voidEthereumAddress) {
    nftReceiver = wAddr;
}

//Now we can transfer our NFT token to the receiver through the ERC1155 safeTransferFrom function to wrap it, no matter if the receiver is the Orchestrator or the Wrapper
await myFavoriteERC1155Token.methods.safeTransferFrom(web3.eth.accounts[0], nftReceiver, objectId, myFavoriteERC1155AmountToWrap, "0x").send();

//It can be also possible to use the safeBatchTransferFrom to wrap multiple NFTs at the same time.
await 
myFavoriteERC1155Token.methods.safeBatchTransferFrom(web3.eth.accounts[0], 
nftReceiver, objectIdArray, myFavoriteERC1155AmountToWrapArray,
"0x").send();
//Now we are sure that the Wrapper exists, we can call the previously created function to easily retrieve it
var collectionAddress = await retrieveLatestWrapperAddress(myFavoriteERC1155Token.options.address);

//Normalize the address for eventual search by address purposes
collectionAddress = web3.utils.toChecksumAddress(collectionAddress);

//Collection category to distinguish all collection types, "W1155" means that this Collection is a Wrapper of ERC1155 NFTs
var collectionCategory = "W1155";

var collectionABI = configuration.W1155ABI;

//The needed basic info to operate are of course the Collection address, category and Smart Contract. They can be of course enriched
var collection = {
    address : collectionAddress,
    category : collectionCategory,
    contract : new web3.eth.Contract(collectionABI, collectionAddress)
};

//Object Id values of ERC1155 Wrapped items are the same of the original ones, so there is no need to retrieve them

//Now you can use the objectId to interact with your balance tokens, e.g. you can retrieve your balance
var myBalanceInCollection = await collection.contract.methods.balanceOf(web3.eth.accounts[0], objecId).call();

//And transfer it to another account
await collection.contract.methods.safeTransferFrom(web3.eth.accounts[0], configuration.receiverAccountAddress, objectId, myBalanceInCollection, "0x").send();                    

Wrap ERC721

//Get my favorite ERC721 address
var myFavoriteERC721Token = new web3.eth.Contract(configuration.ERC721ABI, configuration.myFavoriteERC721Address);

//Get the objectId to wrap
var objectId = configuration.myFavoriteERC721ObjectToWrap;

//ERC721 Tokens can be wrapped in two ways: transferring original NFTs to wrap to Orchestrator or directly to the previously created Wrapper.
//The second way helps to save gas, but can be of course used only if someone has previously wrapped some NFTs of the desired Token.
//So let's start defining the Orchestrator as the default receiver, then try to replace it retrieving the Wrapper, if any.

var nftReceiver = ethItemOrchestrator.options.address;

//For computation operations
var voidEthereumAddress = "0x0000000000000000000000000000000000000000";

//Encapsulate the logic inside a function so we are able to re-use it in future
var retrieveLatestWrapperAddress = async function retrieveLatestWrapperAddress(tokenAddress) {

    //It is always recommended to wrap a token using the latest version of the corresponding model.
    //This info is in the active Factory referenced by the Orchestrator
    var factoryAddress = await ethItemOrchestrator.methods.factory().call();
    var factory = new web3.eth.Contract(configuration.EthItemFactoryABI, factoryAddress);

    //Position 0 is model address, position 1 is model version
    var modelVersion = (await factory.methods.erc721WrapperModel())[1];

    //The EthItem Knowledge Bases, referenced by the Orchestrator, contain all previously wrapped Tokens
    var knowledgeBasesAddresses = await ethItemOrchestrator.methods.knowledgeBases().call();

    //We don't know where the wrapper is located, so we need to search in all existing knowledge bases
    //Knowledge Base has an extremely simple logic, so it shouldn't change frequently and the list stays short
    for(var knowledgeBaseAddress of knowledgeBasesAddresses) {
        var knowledgeBase = new web3.eth.Contract(configuration.EthItemKnowledgeBaseABI, knowledgeBaseAddress);
        var wrapperAddress = await knowledgeBase.methods.wrapper(tokenAddress, modelVersion);
        //If the result is different from address(0), then we found our guy
        if(wrapperAddress !== voidEthereumAddress) {
            return wrapperAddress;
        }
    }
    //Found nothing, returns address(0)
    return voidEthereumAddress;
};

//Use the previously written logic
var wAddr = await retrieveLatestWrapperAddress(myFavoriteERC721Token.options.address);

//If the computation returns an already-created Wrapper, we can save more gas bypassing the Orchestrator as a receiver
if(wAddr !== voidEthereumAddress) {
    nftReceiver = wAddr;
}

//Now we can transfer our NFT token to the receiver through the ERC721 safeTransferFrom function to wrap it, mo matter if the receiver is the Orchestrator or the Wrapper
await myFavoriteERC721Token.methods.safeTransferFrom(web3.eth.accounts[0], nftReceiver, objectId, "0x").send();

//Now we are sure that the Wrapper exists, we can call the previously created function to easily retrieve it
var collectionAddress = await retrieveLatestWrapperAddress(myFavoriteERC721Token.options.address);

//Normalize the address for eventual search by address purposes
collectionAddress = web3.utils.toChecksumAddress(collectionAddress);

//Collection category to distinguish all collection types, "W721" means that this Collection is a Wrapper of ERC721 NFTs
var collectionCategory = "W721";

var collectionABI = configuration.W721ABI;

//The needed basic info to operate are of course the Collection address, category and Smart Contract. They can be of course enriched
var collection = {
    address : collectionAddress,
    category : collectionCategory,
    contract : new web3.eth.Contract(collectionABI, collectionAddress)
};

//Object Id values of ERC721 Wrapped items are the same of the original ones, so there is no need to retrieve them

//Now you can use the objectId to interact with your balance tokens, e.g. you can retrieve your balance
var myBalanceInCollection = await collection.contract.methods.balanceOf(web3.eth.accounts[0], objecId).call();

//And transfer it to another account
await collection.contract.methods.safeTransferFrom(web3.eth.accounts[0], configuration.receiverAccountAddress, objectId, myBalanceInCollection, "0x").send();                   

Unwrap Tokens or ETH Token unwrap logic is the same for ERC20, ERC721 and ERC1155 wrapped tokens. It works by calling the function burn(uint256 objectId, uint256 amount) external; or function burnBatch(uint256[] calldata objectIds, uint256[] calldata amounts) external;

//EthItem Token Standard methods.

var objectIdToBurn = configuration.objectIdToBurn;
var amountToBurn = configuration.amountToBurn;

//Single Unwrap
await collection.methods.burn(objectIdToBurn, amountToBurn).send();

var objectIdArrayToBurn = configuration.objectIdArrayToBurn;
var amountArrayToBurn = configuration.amountArrayToBurn;

//Multiple Unwrap
await collection.methods.burnBatch(objectIdArrayToBurn, amountArrayToBurn).send();                   

The burn and burnBatch operation will burn the wrapped items and gives back to the owner the corresponding amount of original Tokens (or ETHs, in case of ERC20Wrapper).

Last updated