The Spanning Demo App is live! Check it out here: https://demo.spanning.network/
We have also published the open-source demo code and related JavaScript utilities.
Your First Spanning ERC20 - DBUX
This tutorial will walk you through all of the setup necessary to deploy your first Spanning application; a SpanningERC20 token DBUX
. DBUX
is capable of being minted, owned, and transferred to users across the Spanning Network and only requires a single contract deployment.
This is the first of a series of tutorials that will teach you the basics of writing Spanning applications, from smart contracts to frontend deployments. By the end, you will have your own version of this demo application.
Recommended Developer Environment
We recommend using VS Code with the Remix plugin. For a more detailed description of how to set this up, please refer to this tutorial.
The source code and API for the Spanning contracts and base classes can be installed via:
npm install @spanning/contracts
Smart Contract Code
Contract Definition and Imports
Let's start by defining a new contract file called dbux.sol
:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@spanning/contracts/token/ERC20/SpanningERC20.sol"; // Note: the following imports are included via SpanningERC20.sol // but are included here to be explicit import "@spanning/contracts/SpanningUtils.sol"; import "@spanning/contracts/Spanning.sol"; /** * The DBUX contract, utilizing the Spanning Protocol for multichain functionality. */ contract DBUX is SpanningERC20 { }
This defines our new contract as a SpanningERC20 and gives us access to a host of multichain functionality and utilities, but it won't compile yet as we need to define a constructor.
Defining a Spanning Constructor
The constructor of a Solidity smart contract gets run by default when the contract is first instantiated on the blockchain. It allows the owner to pass in custom arguments for their deployment.
A SpanningERC20 constructor takes three arguments:
- The token name
- The token symbol
- The local Spanning Delegate contract address to use for crosschain messaging
Our constructor for DBUX
will take in one argument (the Spanning Delegate contract address) that it will pass to the SpanningERC20 constructor:
/** * @dev Creates the contract, initializing various base contracts. * * @param delegateLegacyAddress - Legacy (local) Address of the Delegate */ constructor(address delegateLegacyAddress) SpanningERC20("Dylan Bux", "DBUX", delegateLegacyAddress) {}
Congratulations! You have now written your first multichain token capable of being owned and transferred between users on any network! There is one more piece of functionality to add so users can get their first DBUX
; minting.
Add Mint Functions
Like all ERC20s, SpanningERC20s have a default _mint
function that can only be called internally. For an external user to access it we must create a new function:
/** * @dev Mint DBUX to a Spanning Address * */ function mint(bytes32 receiverAddress, uint256 amount) public { _mint(receiverAddress, amount); }
This allows a user to mint any amount
of DBUX to the Spanning Address receiverAddress
.
Let's also add some overrides to the mint
function for user convenience.
/** * @dev Mint DBUX to a local user address * * @param receiverLegacyAddress - Legacy (local) address that DBUX is minted to */ function mint(address receiverLegacyAddress, uint256 amount) public { mint(getAddressFromLegacy(receiverLegacyAddress), amount); } /** * @dev Mint DBUX to the transaction sender */ function mint(uint256 amount) public { mint(spanningMsgSender(), amount); }
Here we make use of two helper functions:
- spanningMsgSender() which allows us to get the original message sender Spanning Address that has been validated by the Spanning Network
- getAddressFromLegacy() which creates a Spanning Address for a user based on their local address and the Delegate-verified domain ID
Decimals
We are also going to override the number of decimal places our ERC20 token can have to zero from the default of 18
. This will make it a bit easier to integrate with the final tutorial to build a web app.
/** * @return uint8 - Number of decimals used to get a user representation. */ function decimals() public view virtual override returns (uint8) { return 0; }
DBUX Full Code
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@spanning/contracts/token/ERC20/SpanningERC20.sol"; // Note: the following imports are included via SpanningERC20.sol // but are included here to be explicit import "@spanning/contracts/SpanningUtils.sol"; import "@spanning/contracts/Spanning.sol"; /** * The DBUX contract, utilizing the Spanning Protocol for multichain functionality. */ contract DBUX is SpanningERC20 { /** * @dev Creates the contract, initializing various base contracts. * * @param delegateLegacyAddress - Legacy (local) Address of the Delegate */ constructor(address delegateLegacyAddress) SpanningERC20("Dylan Bux", "DBUX", delegateLegacyAddress) {} /** * @dev Mint DBUX to a Spanning Address * */ function mint(bytes32 receiverAddress, uint256 amount) public { _mint(receiverAddress, amount); } /** * @dev Mint DBUX to a local user address * * @param receiverLegacyAddress - Legacy (local) address that DBUX is minted to */ function mint(address receiverLegacyAddress, uint256 amount) public { mint(getAddressFromLegacy(receiverLegacyAddress), amount); } /** * @dev Mint DBUX to the transaction sender */ function mint(uint256 amount) public { mint(spanningMsgSender(), amount); } /** * @return uint8 - Number of decimals used to get a user representation. */ function decimals() public view virtual override returns (uint8) { return 0; } }
Deploying Your Spanning Token
Your SpanningERC20 token is ready for deployment! The last consideration is where you want to deploy.
Check the latest Spanning Network deployment to see the most up-to-date Spanning Delegate addresses and deployable chains:
Mainnets
Network | Domain ID | Spanning Delegate Address | Spanning Address Library |
---|---|---|---|
Ethereum | 0x00000001 | Coming soon | 0x95e171b7ED0A147B51638d97aed92f15ffDE5f0D |
Avalanche | 0x0000A86A | Coming soon | 0xF7139eA302b6735f57Ee9c563b547b295b25CedC |
Arbitrum One | 0x0000A4B1 | Coming soon | 0x7Cdb610Ebd09B9f813EE2F5764d12898BC0286dC |
Binance Smart Chain | 0x00000038 | Coming soon | 0xF7139eA302b6735f57Ee9c563b547b295b25CedC |
Polygon | 0x00000089 | Coming soon | 0x1Cd3Ce05Ace44c3F4c560B0fcE0F39764030c299 |
Testnets
Network | Domain ID | Spanning Delegate Address |
---|---|---|
Mumbai | 0x00013881 | 0x2e613A930149A86D2fc42Dfbc1C5A63619FB3Bcb |
Fuji | 0x0000A869 | 0x9E6058C2bC70d11C7E2E4fF7128616C290374827 |
Goerli | 0x00000005 | 0x33f69d8e62e38C28bd7f0cbc61af6Eb8a0b3EF77 |
Deployable chains are networks on the Spanning Network that transactions can be written to. To get full multichain functionality, you must deploy your token on a deployable chain. Non-deployable networks can still host SpanningERC20s and be owned and transferred to multichain users, but they will be frozen for remote multichain owners until deployable status is added.
Here let's deploy DBUX
to the Avalanche Fuji testnet. This means we must pass the constructor the Avalanche Fuji Delegate address upon construction.
Connecting VS Code Remix
If you are using VS Code and the Remix plugin, you can launch Remix by clicking the start remixd client
menu option in the Ethereum Remix side menu:

Follow the instructions in your VS Code terminal to go to https://remix.ethereum.org/ and connect to localhost in the File Explorer:

Deploying a Contract on Remix
Open the dbux.sol
file you created, compile and deploy your contract via Injected Web3
while connected to the Fuji Network.
When deploying the contract, make sure to use the correct Spanning Delegate address we got previously. Also, make sure that the contract
being deployed is dbux.sol
. Remix may default to deploying only the IERC20
contract.

You may also need Fuji testnet gas to deploy your application, which you can get here.
Your token is now live! In the next tutorials, we will walk through deploying a SpanningERC721 contract and building a user interface for your tokens that can connect to multiple networks to support multichain users.
Testing
You can test your token by using using the mint
function calls right in Remix, and verify the results by looking at the Snowtrace testnet scanner and plugging in your newly deployed contract address: https://testnet.snowtrace.io/token/<YOUR_CONTRACT_ADDDRESS_HERE>
To test cross-chain functionality easily you can visit delegate.spanning.network which will allow you to submit transactions from any supported network to any smart contract on a deployable network. It can also be used for testing on the same chain if you don't want to go through Remix at all! Find more information about the Delegate App here.