{"id":29182823,"url":"https://github.com/magiclabs/example-arbitrum-guide","last_synced_at":"2025-07-01T20:33:08.930Z","repository":{"id":43688545,"uuid":"391154275","full_name":"magiclabs/example-arbitrum-guide","owner":"magiclabs","description":null,"archived":false,"fork":false,"pushed_at":"2023-07-20T00:53:41.000Z","size":2336,"stargazers_count":2,"open_issues_count":9,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-04-16T01:22:40.302Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/magiclabs.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-30T18:08:07.000Z","updated_at":"2024-04-16T01:22:40.303Z","dependencies_parsed_at":"2024-10-23T03:26:45.276Z","dependency_job_id":null,"html_url":"https://github.com/magiclabs/example-arbitrum-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/magiclabs/example-arbitrum-guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-arbitrum-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-arbitrum-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-arbitrum-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-arbitrum-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/magiclabs","download_url":"https://codeload.github.com/magiclabs/example-arbitrum-guide/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-arbitrum-guide/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263033214,"owners_count":23403116,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-01T20:32:58.776Z","updated_at":"2025-07-01T20:33:08.806Z","avatar_url":"https://github.com/magiclabs.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Resources\n- [GitHub Repo](https://github.com/magiclabs/example-arbitrum-guide)\n\n# Quick Start\n\n```\n$ git clone https://github.com/magiclabs/example-arbitrum-guide.git\n$ cd example-arbitrum-guide\n$ mv .env.local .env // enter your LIVE API Key (from https://dashboard.magic.link)\n$ yarn install\n$ yarn start\n```\n\n# Introduction\n\n## What is Arbitrum\n\n[Arbitrum](https://arbitrum.io) is a new Layer 2 scaling solution for Ethereum, which just launched it's mainnet beta in May 2021. It uses \"optimistic rollups\" technology where transactions are submitted directly to the L2, \"rolled up\" into a single proof, then sent to the layer one chain (Ethereum) to be verified. With smart contract computations being done on L2 rather than L1, it allows for significantly faster and cheaper transactions.\n\nArbitrum is also interoperable with Ethereum and the Ethereum Virtual Machine (EVM) so smart contracts can easily be depolyed on Arbitrum without much/any refactoring.\n\nWith Magic, developers can connect to the Arbitrum network by simply specifying the network URL when initiating a Magic instance. This guide will show how you can create a web3-enabled app, allow users to switch between the Ethereum and Arbitrum networks, call smart contracts, and send transactions. \n\n## Connecting to Ethereum / Arbitrum\n\nIn `magic.js`, we will need two `Magic` and two `Web3` instances, one for each network, since we're allowing users to switch between the two. If you're only interested in connecting to Arbitrum, then only one instance of `Magic` and `Web3` should be created. We also are adding `magicEthereum.network = 'ethereum'` to be able to identify the Magic network we're creating.\n\nYou’ll use the same API key for both `Magic` instances so that the user’s public address does not change. \n\n```js\nimport { Magic } from 'magic-sdk';\nimport Web3 from 'web3';\n\nconst customNodeOptions = {\n  rpcUrl: 'https://goerli-rollup.arbitrum.io/rpc',\n  chainId: 421613,\n};\n\n// Setting network to Arbitrum Testnet\nexport const magicArbitrum = new Magic(process.env.REACT_APP_MAGIC_PUBLISHABLE_KEY, \n  { \n    network: customNodeOptions,\n  },\n);\nmagicArbitrum.network = 'arbitrum';\n\nexport const web3Arbitrum = new Web3(magicArbitrum.rpcProvider);\n\n// Setting network to Ethereum (Goerli Testnet)\nexport const magicEthereum = new Magic(\n  process.env.REACT_APP_MAGIC_PUBLISHABLE_KEY, \n  { \n    network: 'goerli',\n  },\n);\nmagicEthereum.network = 'ethereum';\n\nexport const web3Ethereum = new Web3(magicEthereum.rpcProvider);\n```\n\n## Switching Between Networks\n\nUsers are able to switch between the Ethereum and Arbitrum networks with the `select` element dropdown list. Since one `Magic` instance points towards Ethereum, and the other Arbitrum, we simply update the instance that we’re using for our app based on whichever network the user selects.\n\n```js\nimport { magicEthereum, magicArbitrum } from '../magic';\n\n  const [magic, setMagic] = useState(magicEthereum);\n\n  const handleChangeNetwork = (e) =\u003e {\n    e.target.value === 'ethereum' ? setMagic(magicEthereum) : setMagic(magicArbitrum);\n    fetchBalance(userMetadata.publicAddress);\n    fetchContractMessage();\n  }\n\n  return (\n    \u003cdiv className=\"info\"\u003e\n      \u003cselect name=\"network\" onChange={(e) =\u003e handleChangeNetwork(e)}\u003e\n        \u003coption value=\"ethereum\"\u003eEthereum Testnet (Goerli)\u003c/option\u003e\n        \u003coption value=\"arbitrum\"\u003eArbitrum Testnet\u003c/option\u003e\n      \u003c/select\u003e\n    \u003c/div\u003e\n  )\n```\n\n## Viewing User Balance\n\nA user's public address will be the same on both Ethereum and Arbitrum (as long as you are using the same API key for each instance) so a simple `web3.eth.getBalance` call is all that is needed for either network.\n\n```js\nconst fetchBalance = (address) =\u003e {\n  web3.eth.getBalance(address).then(bal =\u003e setBalance(web3.utils.fromWei(bal)))\n}\n\nreturn (\n\u003ch1\u003eBalance\u003c/h1\u003e\n\u003cdiv className=\"info\"\u003e\n  {balance.toString().substring(0, 6)} ETH\n\u003c/div\u003e\n)\n```\n\n## Send Transaction\n\nSending a transaction is also very simple and similar for both networks. However, one important difference between the two is gas estimates. The gas limit for `sendTransaction` on Ethereum will always be 21000. However Arbitrum uses ArbGas and is calculated differently (see [Arbitrum Docs](https://developer.offchainlabs.com/docs/arbgas)). For this we set a fallback price of `1000000`.\n\n```js\nconst web3 = magic.network === \"ethereum\" ? web3Ethereum : web3Arbitrum;\n\nconst sendTransaction = async () =\u003e {\n  if (!toAddress || !amount) return;\n  const { transactionHash } = await web3.eth.sendTransaction({\n    from: publicAddress,\n    to: toAddress,\n    value: web3.utils.toWei(amount),\n    gasLimit: network === 'ethereum' ? 21000 : 1000000\n  });\n}\n\nreturn (\n \u003cdiv className=\"container\"\u003e\n  \u003ch1\u003eSend Transaction\u003c/h1\u003e\n  \u003cinput \n    type=\"text\" \n    value={toAddress} \n    onChange={(e) =\u003e setToAddress(e.target.value)} \n    placeholder=\"To Address\" \n  /\u003e\n  \u003cinput \n    type=\"text\" \n    value={amount} \n    onChange={(e) =\u003e setAmount(e.target.value)} \n    placeholder=\"Amount\" \n  /\u003e\n  \u003cbutton onClick={sendTransaction}\u003eSend Transaction\u003c/button\u003e\n\u003c/div\u003e\n)\n```\n\n## Calling Smart Contracts\n\nSeparate smart contracts will need to be deployed on each Ethereum and Arbitrum for your users to interact with them, so you'll need to know the address of each in order to call it. \n\n```js\nconst [message, setMessage] = useState('...');\nconst [newMessage, setNewMessage] = useState('');\nconst network = magic.network === 'ethereum' ? 'ethereum' : 'arbitrum';\nconst ethContractAddress = '0x7aCDA8b3d17A8680a0033b57A693c97dD2b239c3';\nconst arbitrumContractAddress = '0xaFcf48c7e0eABe6Cd77F539Ab2D8e29c8D5197Dc';\nconst contract = new web3.eth.Contract(abi, network === 'ethereum' ? ethContractAddress : arbitrumContractAddress);\n\n// Grabbing `message` variable value stored in the smart contract\nconst fetchContractMessage = () =\u003e contract.methods.message().call().then(setMessage)\n\n// Update contract `message` value on the blockchain\nconst updateContractMessage = async () =\u003e {\n  if (!newMessage) return;\n  const { transactionHash } = await contract.methods.update(newMessage).send({ \n    from: publicAddress, \n    gasLimit: network === 'ethereum' ? web3.eth.getBlock(\"latest\").gasLimit : 1000000 \n  });\n}\n\nreturn (\n  \u003ch1\u003eContract Message\u003c/h1\u003e\n  \u003cdiv className=\"info\"\u003e{message}\u003c/div\u003e\n\n  \u003ch1\u003eUpdate Message\u003c/h1\u003e\n  \u003cinput \n    type=\"text\" \n    value={newMessage} \n    onChange={(e) =\u003e setNewMessage(e.target.value)} \n    placeholder=\"New Message\" /\u003e\n\n  \u003cbutton onClick={updateContractMessage}\u003eUpdate\u003c/button\u003e\n)\n```\n\n## Done\n\nThat's all there is to it! You've now got an app that allows users to create a wallet with just their email, and connect to the Arbitrum L2 and Ethereum networks within your app.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagiclabs%2Fexample-arbitrum-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmagiclabs%2Fexample-arbitrum-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagiclabs%2Fexample-arbitrum-guide/lists"}