How To Build and Deploy a Smart Contract on Arbitrum
Arbitrum is an Ethereum layer-2 network that enables developers to build and deploy highly scalable smart contracts at low cost. With Chainlink Data Feeds on Arbitrum, developers can quickly and easily connect their smart contracts to off-chain data, including hyper-reliable asset prices that can be used to build a plethora of DeFi applications.
In this technical article, we’ll explain what Arbitrum is, go through how to get started on the Arbitrum Rinkeby Testnet, and give you a step-by-step walkthrough of how to use Chainlink Price Feeds in your Arbitrum smart contracts. While in this article we will build and deploy in a testnet environment, the steps are the same for Arbitrum One Mainnet.
What Is Arbitrum?
Arbitrum is an Optimistic rollup Ethereum layer-2 solution. Several scaling solutions have sprung up to offer enhanced speed and lower cost on the Ethereum blockchain, including layer-2 rollups, state (and payment) channels, sidechains, Plasma, and Validium. The most important difference between these solutions is that rollups and state channels inherit the security of the layer-1 Ethereum blockchain, enabling developers to essentially build on top of the base Ethereum layer.
Layer-2 rollups consist of Optimistic rollups and ZK-rollups. Both are “true layer-2 solutions”, which means they are able to execute a large volume of transactions at high speed and low cost and then verify this bundle of transactions on layer 1. With Optimistic rollups, we “optimistically believe” that these transactions really happened on layer 2. These rollups are “optimistic” because the bundles are considered “innocent until proven guilty” by fraud proofs and are optimistically assumed to be correct when posted to layer 1 unless a challenge has been submitted during the 7-day challenge period.
Getting Started With Arbitrum
In this tutorial, we are going to build and deploy a smart contract on Arbitrum Rinkeby Testnet, which is a layer 2 for Rinkeby testnet. The same steps apply for Arbitrum One, a layer 2 for Ethereum mainnet. To use Arbitrum Rinkeby Testnet we need some Rinkeby test ETH. You can attain your Rinkeby test LINK through Chainlink Faucets—simply paste your wallet address, select Rinkeby Ethereum, and claim your test ETH.
We then need to deposit test ETH from Rinkeby in order to pay fees on Arbitrum Rinkeby Testnet. Navigate to the Arbitrum bridge, connect your wallet, enter the amount of Rinkeby ETH you require and click “Deposit”. It will be approximately 10 minutes before you see your balance credited on layer 2—time for a coffee break.
Once you’ve received your layer-2 ETH, configure your Metamask wallet to Arbitrum Rinkeby testnet. Either navigate to Chainlist and find the details for Arbitrum Rinkeby Network or navigate to Etherscan explorer and either find Add Arbitrum Network in the website’s footer or select Settings -> Networks -> Add Network in Metamask and then enter the details manually.
Network Name: Arbitrum Rinkeby Testnet
Network URL: https://rinkeby.arbitrum.io/rpc
Chain ID: 421611
Currency Symbol: ETH
Block Explorer URL: https://testnet.arbiscan.io/
Finally, return to Chainlink Faucets, select Arbitrum Rinkeby, and claim 10 test LINK tokens.
The Importance of Accurate and Reliable Price Data in Smart Contracts
To expand the horizons of what’s possible with smart contracts on layer 2, developers need a secure connection to off-chain resources. With highly accurate and reliable price data from Chainlink oracles, developers can begin building and testing a wide range of scalable DeFi applications on Arbitrum that rely on the price of ETH and other tokens, such as lending protocols, decentralized exchanges, prediction markets, and more.
While these DeFi use cases require external data, blockchains and layer-2 solutions are not able to natively access data outside themselves. When data is provided to blockchains to facilitate advanced DeFi use cases, it’s imperative that it’s secure and of high quality in order to prevent price oracle attacks.
Chainlink Price Feeds mitigate the risk of these attacks by providing aggregated data from various high-quality data providers, fed on-chain by decentralized oracles through the Chainlink Network. Chainlink’s decentralized oracle mechanism ensures the final price values reflect broad market coverage, meaning the final price is determined after aggregating a diverse set of prices across the entire market rather than just a small subset, with other aspects such as volume and liquidity also taken into account. With Chainlink Price Feeds, developers are able to build advanced DeFi applications that don’t compromise on security.
Now that we understand the need for accurate and reliable price data in Solidity smart contracts and the important role that Chainlink price oracles play, we’ll go through an example of using a Chainlink Price Feed to obtain the latest price of ETH in a Solidity smart contract on Arbitrum.
Using Chainlink Price Feeds on Arbitrum
Start by creating a new Solidity project in your favorite code editor. The full example using Hardhat with Typescript is available on Github. We are going to use the latest versions of Solidity and Chainlink.
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
Now we are going to write a function to retrieve Price Feeds data from the Chainlink Network. Navigate to the Data Feeds section of the official Chainlink documentation. We are going to take the example for the “getPrice” function and slightly modify it.
function getThePrice(address _priceFeedAddress) public view returns (int) { AggregatorV3Interface priceFeed = AggregatorV3Interface(_priceFeedAddress); ( uint80 roundID, int price, uint startedAt, uint updatedAt, uint80 answeredInRound ) = priceFeed.latestRoundData(); return price; }
You can see that we are passing the “priceFeedAddress” as a parameter to make this smart contract more scalable. You can see the full list of all Price Feed addresses available on Arbitrum Rinkeby Testnet here.
For example, if we want to know the price of BTC in USD we can pass “0x0c9973e7a27d00e656B9f153348dA46CaD70d03d” to our function as “_priceFeedAddress” parameter.
Almost Done! Meet the L2 Sequencer Health Flag
Transactions in Arbitrum are confirmed at a high speed. This is because of the so-called Sequencer. The Sequencer is an off-chain component that is able to order user transactions and give users receipts at high speed. However, if the Sequencer is not available, users have to submit their transactions through Ethereum in order to have them processed in Arbitrum. This is detrimental to user experience, and many dApps still don’t have the affordances to interact with both Ethereum and Arbitrum in parallel.
If you don’t want to worry about this in your application, you can use a Chainlink oracle to be sure that the Sequencer is available for users. Here are the steps to do so:
First, we need to add the next import statement to our Solidity code
import "@chainlink/contracts/src/v0.8/interfaces/FlagsInterface.sol";
According to the Chainlink docs, The L2 Sequencer Health Flag consists of three actors:
- Chainlink Cluster (a group of validator nodes)—this executes the OCR Job every heartbeat “T” (the minimum frequency at which the Chainlink feed is configured to be updated).
- The actual OCR feed reporting the Sequencer status—this could be used for external users on layer 1 to check OR protocol (e.g. Arbitrum) status.
- Validator—this gets triggered by the OCR feed and executes the raise or lower flag action if the current answer is different from the previous one.
Now, we need to expand our contract with the next lines
// Identifier of the Sequencer offline flag on the Flags contract address constant private FLAG_ARBITRUM_SEQ_OFFLINE = address(bytes20(bytes32(uint256(keccak256("chainlink.flags.arbitrum-seq-offline")) - 1))); FlagsInterface internal chainlinkFlags; constructor() { chainlinkFlags = FlagsInterface(0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b); }
“0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b” is the address of the Arbitrum Rinkeby Flags Contract. To check the other addresses, head to the Chainlink Docs.
A raised flag indicates that the feed wasn’t updated in “T” time and its data can be considered stale. In other words, the Sequencer went offline and your contract shouldn’t perform any critical operations. When the Sequencer comes back up again and the layer-2 Chainlink Data Feeds are updated, you can continue using your contracts as usual. Let’s add that extra check.
function getThePrice(address _priceFeedAddress) public view returns (int) { bool isRaised = chainlinkFlags.getFlag(FLAG_ARBITRUM_SEQ_OFFLINE); if (isRaised) { // If flag is raised we shouldn't perform any critical operations revert("Chainlink feeds are not being updated"); } AggregatorV3Interface priceFeed = AggregatorV3Interface(_priceFeedAddress); ( uint80 roundID, int price, uint startedAt, uint updatedAt, uint80 answeredInRound ) = priceFeed.latestRoundData(); return price; }
Deploying and Testing the Smart Contract
Now we are ready to deploy and test our contract. Compile the contract in Remix, then, on the deployment tab, change the environment to “Injected Web3”. Ensure that the wallet is connected to Arbitrum Rinkeby Testnet and that the wallet address below is for the MetaMask wallet containing the ETH obtained earlier. Then, press the deploy button and follow the steps.
The end result is a successful transaction and smart contract deployed to the Arbitrum Rinkeby Testnet.
To test it out we simply need to call our “getThePrice” function and pass one of the Chainlink Price Feed addresses on Arbitrum Rinkeby Testnet as the “_priceFeedAddress” parameter. Remember, you can see all of the available Price Feed addresses in the Chainlink Docs.
Summary
Chainlink’s popular ETH/USD Price Feed as well as Price Feeds for LINK/USD, AAVE/USD, and BTC/USD are all available on Arbitrum. These Chainlink Price Feeds are built upon decentralized oracle infrastructure that consists of numerous security-reviewed node operators and premium data sources, leading to highly accurate, available, and tamper-resistant data feeds that are inherently resistant to vulnerabilities like flash loan-induced price manipulation attacks.
This technical tutorial has demonstrated how easy it is to write and deploy hybrid smart contracts on Arbitrum. With this knowledge, you’ll be able to start building your own smart contracts that take advantage of the low cost and high speed of Arbitrum and the advanced utility unlocked by Chainlink Price Feeds.
Learn more about Chainlink by visiting chain.link or read the documentation at docs.chain.link. To discuss an integration, reach out to an expert.