> ## Documentation Index
> Fetch the complete documentation index at: https://docs.skale.space/llms.txt
> Use this file to discover all available pages before exploring further.

# Bridge ERC-1155 Tokens

> Guide on bridging ERC-1155 tokens on SKALE

SKALE's Interchain Messaging Agent (IMA) Bridge allows for direct communication and bridging between SKALE Chains (without ever going to Mainnet).

The following walks you through setting up an ERC-1155 token between two SKALE Chains and how to programatically bridge.

## Important Information

* When a SKALE Chain is created, there are no ERC-1155 tokens mapped by default
* A token being bridged between two chains should have its supply **issued** (i.e minted) on one chain. The second SKALE Chain mints by design via IMA, however, the token should not be mintable any other way
* Tokens being bridged from SKALE Chain to SKALE Chain are locked in TokenManagerERC1155 on the origin chain
* Tokens being bridged from SKALE Chain to SKALE Chain are minted by IMA on the destination chain

## Bridge Setup

<Note>
  If the SKALE Chains you are mapping the ERC-1155 token from/to are not connected, please [connect the SKALE Chains](/developers/skale-bridge/skale/connect-schains).
</Note>

### 1. Prepare the ERC-1155

ERC-1155 tokens that are being bridged between SKALE Chains should have the **mint** function that is locked down to TokenManagerERC1155.

<Danger>
  If the mint function is not locked down to just the IMA Bridge, specifically TokenManagerERC1155; there is a chance that the existing tokens on the SKALE Chain may not match what is secured in the bridge.
</Danger>

<Warning>
  If the burn function is not locked down to just the IMA Bridge, specifically TokenManagerERC1155; there is a chance that the supply on the SKALE Chain side could be "burned", while the tokens still exist on the original SKALE Chain which could later be withdrawn under certain circumstances. It is recommended that explicit burns on a SKALE Chain should be avoided for bridged tokens.
</Warning>

The following is the base interchain token code that meets the above bridging requirements for IMA. It is not recommended to use this directly, but to use a wrapper. See **YourInterchainNFT.sol** for an example.

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155.sol";
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";

contract InterchainERC1155 is AccessControl, ERC1155 {
    using Strings for uint256;

    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    string private _baseUri;

    constructor(string memory baseUri) ERC1155("") {
        _grantRole(MINTER_ROLE, 0xD2aaA00900000000000000000000000000000000);
        _baseUri = baseUri; // e.g. "ipfs://QmSomeCID/"
    }

    function uri(uint256 tokenId) public view override returns (string memory) {
        return string(abi.encodePacked(_baseUri, tokenId.toString(), ".json"));
    }

    function mint(
        address account,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) external {
        require(hasRole(MINTER_ROLE, _msgSender()), "Sender is not a Minter");
        _mint(account, id, amount, data);
    }

    function mintBatch(
        address account,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) external {
        require(hasRole(MINTER_ROLE, _msgSender()), "Sender is not a Minter");
        _mintBatch(account, ids, amounts, data);
    }

    function setBaseUri(string memory newBaseUri) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _baseUri = newBaseUri;
    }
}
```

### 2. Deploy the ERC-1155 on SKALE

Utilize your preferred tooling i.e [Foundry](https://getfoundry.sh), [Hardhat](https://hardhat.org), [Remix](https://remix.ethereum.org/#lang=en\&optimize=false\&runs=200\&evmVersion=paris\&version=soljson-v0.8.19+commit.7dd6d404.js), etc. to deploy your IMA compatible ERC-1155 token to the SKALE Chain you want to be able to bridge assets too.

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import { InterchainERC1155 } from "./InterchainERC1155.sol";

contract InGameTokens is InterchainERC1155("ipfs://<cid>") {}
```

> *InterchainERC1155.sol is inherited from the code above*

### 3. Map the SKALE Token

<Note>
  If you are trying to setup a token on SKALE in a production environment please join us in [Discord](https://discord.gg/skale) for support!
</Note>

<Warning>
  Make sure to replace the values with your SKALE Chain name and the correct token addresses.
</Warning>

#### Add the token on SKALE Chain TokenManagerERC1155

* **DST\_SCHAIN\_NAME** is the name of the SKALE Chain that the transaction should execute on
* **ORIGIN\_SCHAIN\_NAME** is the name of the SKALE Chain that the token is being mapped from
* **0x\_ORIGIN\_TOKEN** is the original token address on the ORIGIN\_SCHAIN\_NAME
* **0x\_DST\_TOKEN** is the destination token address on the DST\_SCHAIN\_NAME

<Tabs>
  <Tab title="Multisigwallet CLI">
    ## Multisigwallet CLI

    ```shell theme={null}
    npx msig encodeData [DST_SCHAIN_NAME] TokenManagerERC1155 addERC20TokenByOwner [ORIGIN_SCHAIN_NAME] [0x_ORIGIN_TOKEN] [0x_DST_TOKEN]
    ```
  </Tab>
</Tabs>

After this, execute by following the steps on [Using SAFE](/developers/run-a-skale-chain/using-safe#submit-transaction-to-safe)

#### Verify the Mapping

To verify the mapping, you should have an event emitted from TokenManagerERC1155 on SKALE Chain - `event ERC1155TokenAdded(SchainHash indexed chainHash, address indexed erc1155OnMainChain, address indexed erc1155OnSchain);`

## Bridging ERC-1155

The following does not require you to setup your own token. This works with **ANY** ERC-1155 token that is mapped from a SKALE Chain to any other SKALE Chain as long as the actual ERC-1155 token on each side does not have additional restrictions around who can transfer.

The flow for bridging an ERC-1155 from SKALE Chain to SKALE Chain follows a very similar flow to a standard ERC-1155 transfer:

1. Approve the bridge contract on the ERC-1155 token to allow it to move your NFTs
2. Call the bridge directly to transfer the specific ERC-1155 from SKALE Chain -> SKALE Chain, if the mapping exists
3. Wait for the message to be posted by the validator set on the SKALE Chain, which is the net-new minted NFT corresponding to the NFT (by id) locked on the origin SKALE Chain during the bridge

### Bridge Tokens

The following will help you bridge an ERC-1155 NFT from one SKALE Chain to another.

<Tabs>
  <Tab title="bridge.js">
    ```js theme={null}
    import { Contract, JsonRpcProvider, Wallet } from "ethers"; // npm add ethers

    const PRIVATE_KEY = "[YOUR_PRIVATE_KEY]";
    const ORIGIN_SCHAIN_RPC_URL = "[YOUR_RPC_URL]";
    const ERC1155_ADDRESS = "[ORIGIN_TOKEN_ADDRESS]";
    const ERC1155_ABI = [ "function setApprovalForAll(address operator, bool approved) external" ];
    const TOKEN_MANAGER_ERC1155_ADDRESS = "0xD2aaA00900000000000000000000000000000000"; // DO NOT CHANGE THIS
    const TOKEN_MANAGER_ERC1155_ABI = [ "function transferToSchainERC1155(string calldata targetSchainName, address contractOnMainnet, uint256 id, uint256 amount) external" ];
    const DST_SKALE_CHAIN_NAME = "[DST_SKALE_CHAIN_NAME]"; // e.g green-giddy-denebola (nebula mainnnet);
    const NUMBER_TOKENS_TO_TRANSFER = parseEther("100"); // 100 tokens in wei format
    const TOKEN_ID = BigInt(1);

    // Setup the RPC Provider to connect to Ethereum
    const provider = new JsonRpcProvider(ORIGIN_SCHAIN_RPC_URL);

    // Setup the wallet with your private key and default to the Ethereum provider
    const wallet = new Wallet(PRIVATE_KEY, provider);

    // Setup the smart contracts which default to being signed by your wallet and connected on Ethereum
    const tokenManagerContract = new Contract(TOKEN_MANAGER_ERC1155_ADDRESS, TOKEN_MANAGER_ERC1155_ABI, wallet);
    const tokenContract = new Contract(ERC1155_ADDRESS, ERC1155_ABI, wallet);

    // 1. Approve the bridge to move ERC-1155 Tokens
    const approvalTx = await tokenContract.setApprovalForAll(TOKEN_MANAGER_ERC1155_ADDRESS, true);
    await approvalTx.wait(1); // Wait 1 blocks for confirmation, ~1 seconds

    // 2. Bridge 100 of ERC-1155 Token Id #1, will receive on same address on new skale chain
    const bridgeTx = await tokenManagerContract.transferToSchainERC1155(DST_SKALE_CHAIN_NAME, ERC1155_ADDRESS, TOKEN_ID, NUMBER_TOKENS_TO_TRANSFER);
    await bridgeTx.wait(1); // Wait 1 blocks for confirmation, ~1 seconds

    // Success! Now watch for delivery on Destination Chain
    console.log("Success!");
    ```
  </Tab>

  <Tab title="bridgeBatch.js">
    ```js theme={null}
    import { Contract, JsonRpcProvider, Wallet } from "ethers"; // npm add ethers

    const PRIVATE_KEY = "[YOUR_PRIVATE_KEY]";
    const ORIGIN_SCHAIN_RPC_URL = "[YOUR_RPC_URL]";
    const ERC1155_ADDRESS = "[ORIGIN_TOKEN_ADDRESS]";
    const ERC1155_ABI = [ "function setApprovalForAll(address operator, bool approved) external" ];
    const TOKEN_MANAGER_ERC1155_ADDRESS = "0xD2aaA00900000000000000000000000000000000"; // DO NOT CHANGE THIS
    const TOKEN_MANAGER_ERC1155_ABI = [ "function transferToSchainERC1155Batch(string calldata targetSchainName, address contractOnMainnet, uint256[] calldata ids, uint256[] calldata amounts) external" ];
    const DST_SKALE_CHAIN_NAME = "[DST_SKALE_CHAIN_NAME]"; // e.g green-giddy-denebola (nebula mainnnet);
    const NUMBER_TOKENS_TO_TRANSFER = [parseEther("5"), parseEther("100")]; // 100 tokens in wei format
    const TOKEN_IDS = [BigInt(1), BigInt(5)];

    // Setup the RPC Provider to connect to Ethereum
    const provider = new JsonRpcProvider(ORIGIN_SCHAIN_RPC_URL);

    // Setup the wallet with your private key and default to the Ethereum provider
    const wallet = new Wallet(PRIVATE_KEY, provider);

    // Setup the smart contracts which default to being signed by your wallet and connected on Ethereum
    const tokenManagerContract = new Contract(TOKEN_MANAGER_ERC1155_ADDRESS, TOKEN_MANAGER_ERC1155_ABI, wallet);
    const tokenContract = new Contract(ERC1155_ADDRESS, ERC1155_ABI, wallet);

    // 1. Approve the bridge to move ERC-1155 Tokens
    const approvalTx = await tokenContract.setApprovalForAll(TOKEN_MANAGER_ERC1155_ADDRESS, true);
    await approvalTx.wait(1); // Wait 1 blocks for confirmation, ~1 seconds

    // 2. Bridge 5 of ERC-1155 Token Id #1 and 100 of Token Id #5, will receive on same address on new skale chain
    const bridgeTx = await tokenManagerContract.transferToSchainERC1155Batch(DST_SKALE_CHAIN_NAME, ERC1155_ADDRESS, TOKEN_IDS, NUMBER_TOKENS_TO_TRANSFER);
    await bridgeTx.wait(1); // Wait 1 blocks for confirmation, ~1 seconds

    // Success! Now watch for delivery on Destination Chain
    console.log("Success!");
    ```
  </Tab>
</Tabs>
