SKALE Chain to SKALE Chain ERC1155 Transfer

As a SKALE chain Owner, there are two main steps to managing SKALE Chain to SKALE Chain (S2S) ERC1155 transfer through IMA:

Once you have completed step 1 to setup ERC1155 tokens with another chain, end-users can transfer ERC1155 tokens between SKALE Chains.

Setup ERC1155 S2S Transfers

The following one-time setup is required for SKALE Chains with a default access control policy (default settings are: whitelisting enabled, automatic deployment disabled). For more information on IMA access control, see here.

1. Enable Automatic Deploy

There are several limits to using automatic deployment. When using this method:

First, enable automatic deploy on the origin chain.

Only the AUTOMATIC_DEPLOYER_ROLE may enable or disable automatic deployment.
  • IMA-JS

  • Web3 JS

// import & init ima-js here

export async function enableAutomaticDeployERC20(ima) {
    let address = "YOUR_ADDRESS";
    let privateKey = "YOUR_PRIVATE_KEY";

    let txOpts = {
        address: address,
        privateKey: privateKey // remove privateKey from txOpts to use Metamask signing
    };

    await ima.schain.enableAutomaticDeploy("ERC20", txOpts);
}
// TODO

2. Connect the target SKALE chain

Add the target chain by using connectSchain within the TokenManagerLinker contract on the origin chain.

Only the REGISTRAR_ROLE may execute connectSchain.
  • IMA-JS

  • Web3 JS

// TODO
const Web3 = require('web3');
const Tx = require('ethereumjs-tx').Transaction;

let schainABIs = require("[YOUR_SKALE_CHAIN_ABIs]");
let privateKey = Buffer.from('[YOUR_PRIVATE_KEY]', 'hex')
let account = "[YOUR_ACCOUNT_ADDRESS]";
let schainEndpoint = "[YOUR_SKALE_CHAIN_ENDPOINT]";
let chainId = "ORIGIN_CHAIN_ID";
let targetSchainName = "TARGET_SKALE_CHAIN_NAME";

const tokenManagerLinkerAddress = schainABIs.token_manager_linker_address;
const tokenManagerLinkerABI = schainABIs.token_manager_linker_abi;

const web3 = new Web3(new Web3.providers.HttpProvider(schainEndpoint));

let contract = new web3.eth.Contract(
  tokenManagerLinkerABI, 
  tokenManagerLinkerAddress
);

/* 
 * Prepare connectSchain
 */
let connectSchain = contract.methods.connectSchain(targetSchainName)
  .encodeABI();  

//get nonce
web3.eth.getTransactionCount(account).then((nonce) => {
  //create raw transaction
  const rawTx = {
    chainId: chainId,
    nonce: "0x" + nonce.toString(16),
    from: account, 
    nonce: "0x" + nonce.toString(16),
    data : connectSchain,
    to: tokenManagerLinkerAddress,
    gasPrice: 100000000000,
    gas: 8000000
  }

  //sign transaction
  const tx = new Tx(rawTx);
  tx.sign(privateKey);

  //serialize transaction
  const serializedTx = tx.serialize();

  //send signed transaction
  web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')).
    on('receipt', receipt => {
      //record receipt to console
      console.log(receipt);
   }).
    catch(console.error);
});

Get Started with S2S ERC1155 Transfer

Be sure to follow any one-time setup and mapping steps described here before initiating S2S transfers.

1. S2S Transfer ERC1155 From Origin

To send ERC1155 tokens from a user’s wallet to another SKALE Chain, you will need to use the transferToSchainERC1155 function within the TokenManagerERC1155 IMA contract on the origin chain.

This method is called from the origin chain to move ERC1155 tokens to a target chain.

The TokenManagerERC1155 contract is predeployed on each SKALE Chain. To get the SKALE Chain ABIs, check out the current release page.

  • IMA-JS

  • Web3 JS

// todo
const Web3 = require("web3");
const Tx = require("ethereumjs-tx").Transaction;

let originABIs = "IMA_ABI_ON_ORIGIN";
let originERC1155ABI = "ERC1155_ABI_ON_ORIGIN";

let privateKey = Buffer.from("END_USER_PRIVATE_KEY", 'hex')
let address = "ADDRESS";

let origin = "ORIGIN_ENDPOINT";
let targetChainName = "TARGET_CHAIN_NAME";
let originChainId = "ORIGIN_CHAIN_ID";

const tokenManagerAddress = originABIs.token_manager_erc1155_address;
const tokenManagerABI = originABIs.token_manager_erc1155_abi;

const erc1155ABI = originERC1155ABI.erc1155_abi;
const erc1155Address = originERC1155ABI.erc1155_address;
const tokenId = "TOKEN_ID";

const web3ForOrigin = new Web3(origin);

let tokenManager = new web3ForOrigin.eth.Contract(
    tokenManagerABI,
    tokenManagerAddress
);

const customCommon = Common.forCustomChain(
    "mainnet", {
        name: "skale-network",
        chainId: originChainId
    },
    "istanbul"
);

let contractERC1155 = new web3ForOrigin.eth.Contract(erc1155ABI, erc1155Address);

let approve = contractERC1155.methods
    .approve(
        tokenManagerAddress,
        tokenId,
        web3ForOrigin.utils.toHex(web3ForOrigin.utils.toWei("1", "ether"))
    )
    .encodeABI();

let transfer = tokenManager.methods
    .transferToSchainERC1155(
        targetChainName,
        erc1155Address,
        tokenId,
        web3ForOrigin.utils.toHex(web3ForOrigin.utils.toWei("1", "ether"))
    )
    .encodeABI();

web3ForOrigin.eth.getTransactionCount(address).then(nonce => {
    //create raw transaction
    const rawTxApprove = {
        chainId: originChainId,
        from: address,
        nonce: "0x" + nonce.toString(16),
        data: approve,
        to: erc1155Address,
        gas: 6500000,
        gasPrice: 100000000000
    };

    //sign transaction
    const txApprove = new Tx(rawTxApprove, {
        common: customCommon
    });
    txApprove.sign(privateKey);

    const serializedTxApprove = txApprove.serialize();

    //send signed transaction (approve)
    web3ForOrigin.eth
        .sendSignedTransaction("0x" + serializedTxApprove.toString("hex"))
        .on("receipt", receipt => {
            console.log(receipt);
            web3ForOrigin.eth
                .getTransactionCount(address)
                .then(nonce => {
                    const rawTxDeposit = {
                        chainId: originChainId,
                        from: address,
                        nonce: "0x" + nonce.toString(16),
                        data: transfer,
                        to: tokenManagerAddress,
                        gas: 6500000,
                        gasPrice: 100000000000
                    };

                    //sign transaction
                    const txDeposit = new Tx(rawTxDeposit, {
                        common: customCommon
                    });

                    txDeposit.sign(privateKey);

                    const serializedTxDeposit = txDeposit.serialize();

                    //send signed transaction (deposit)
                    web3ForOrigin.eth
                        .sendSignedTransaction("0x" + serializedTxDeposit
                            .toString("hex"))
                        .on("receipt", receipt => {
                            console.log(receipt);
                        })
                        .catch(console.error);
                });
        })
        .catch(console.error);
});

2. Exit from SKALE Chain

To exit ERC1155 tokens back to the origin chain, you will need to use the transferToSchainERC1155 function within the TokenManagerERC1155 IMA contract on the target chain, and specify the erc1155Address on the origin chain.

The TokenManagerERC1155 IMA contract is pre-deployed to your SKALE Chain. Please reach out to your account manager to receive the ABIs specific for your SKALE Chain.

  • IMA-JS

  • Web3 JS

// todo
const Web3 = require("web3");
const Tx = require("ethereumjs-tx").Transaction;

let targetABIs = "IMA_ABI_ON_TARGET";
let originERC1155ABI = "ERC1155_ABI_ON_ORIGIN";

let privateKey = Buffer.from("END_USER_PRIVATE_KEY", 'hex')
let address = "ADDRESS";

let target = "TARGET_ENDPOINT";
let originChainName = "ORIGIN_CHAIN_NAME";
let targetChainId = "TARGET_CHAIN_ID";

const tokenManagerAddress = targetABIs.token_manager_erc1155_address;
const tokenManagerABI = targetABIs.token_manager_erc1155_abi;

const erc1155ABI = targetERC1155ABI.erc1155_abi;
const erc1155TargetAddress = targetERC1155ABI.erc1155_address;
const erc1155OriginAddress = originERC1155ABI.erc1155_address;
const tokenId = "TOKEN_ID";

const web3ForTarget = new Web3(target);

let tokenManager = new web3ForTarget.eth.Contract(
    tokenManagerABI,
    tokenManagerAddress
);

const customCommon = Common.forCustomChain(
    "mainnet", {
        name: "skale-network",
        chainId: targetChainId
    },
    "istanbul"
);

let contractERC1155 = new web3ForTarget.eth.Contract(erc1155ABI, erc1155TargetAddress);

let approve = contractERC1155.methods
    .approve(
        tokenManagerAddress,
        tokenId,
        web3ForTarget.utils.toHex(web3ForTarget.utils.toWei("1", "ether"))
    )
    .encodeABI();

let transfer = tokenManager.methods
    .transferToSchainERC1155(
        originChainName,
        erc1155OriginAddress,
        tokenId,
        web3ForTarget.utils.toHex(web3ForTarget.utils.toWei("1", "ether"))
    )
    .encodeABI();

    web3ForTarget.eth.getTransactionCount(address).then(nonce => {
    //create raw transaction
    const rawTxApprove = {
        chainId: targetChainId,
        from: address,
        nonce: "0x" + nonce.toString(16),
        data: approve,
        to: erc1155Address,
        gas: 6500000,
        gasPrice: 100000000000
    };

    //sign transaction
    const txApprove = new Tx(rawTxApprove, {
        common: customCommon
    });
    txApprove.sign(privateKey);

    const serializedTxApprove = txApprove.serialize();

    //send signed transaction (approve)
    web3ForTarget.eth
        .sendSignedTransaction("0x" + serializedTxApprove.toString("hex"))
        .on("receipt", receipt => {
            console.log(receipt);
            web3ForTarget.eth
                .getTransactionCount(address)
                .then(nonce => {
                    const rawTxDeposit = {
                        chainId: targetChainId,
                        from: address,
                        nonce: "0x" + nonce.toString(16),
                        data: transfer,
                        to: tokenManagerAddress,
                        gas: 6500000,
                        gasPrice: 100000000000
                    };

                    //sign transaction
                    const txDeposit = new Tx(rawTxDeposit, {
                        common: customCommon
                    });

                    txDeposit.sign(privateKey);

                    const serializedTxDeposit = txDeposit.serialize();

                    //send signed transaction (deposit)
                    web3ForTarget.eth
                        .sendSignedTransaction("0x" + serializedTxDeposit
                            .toString("hex"))
                        .on("receipt", receipt => {
                            console.log(receipt);
                        })
                        .catch(console.error);
                });
        })
        .catch(console.error);
});