How to Integrate with the Ethereum Blockchain using Javascript

How to Integrate with the Ethereum Blockchain using Javascript

#Installation

To interact with the EVM network, you can use either ethers.js or web3.js libraries with Magic.

⁠To get started, install the following dependencies for your project:

#Ethers.js

NPM
Yarn
CDN
01npm install ethers magic-sdk

#Web3.js

NPM
Yarn
CDN
01npm install web3 magic-sdk

#Initialization

The Magic class is the entry-point to the Magic SDK. It must be instantiated with a Magic publishable key.

important

Ethereum provider is only supported in [email protected] or later versions.

#Ethers.js

#ES Modules/TypeScript

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);

#CommonJS

Ethers (v6)
Ethers (v5)
01const { Magic } = require('magic-sdk');
02const ethers = require('ethers');
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);

#Web3.js

#ES Modules/TypeScript

Typescript
01import { Magic } from 'magic-sdk';
02import Web3 from 'web3';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider); // Or window.web3 = ...

#CommonJS

Typescript
01const { Magic } = require('magic-sdk');
02const Web3 = require('web3');
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider); // Or window.web3 = ...

#Mainnet

Mainnet Block Explorer: https://etherscan.io

Javascript
01const magic = new Magic('YOUR_PUBLISHABLE_API_KEY', {
02  network: 'mainnet', 
03});
04
05// Magic's node infrastructure maps 'mainnet' and 'testnet' to 2 unique set of addresses.

#Testnet

Sepolia Block Explorer: https://sepolia.etherscan.io/

Sepolia Testnet Faucet: https://sepoliafaucet.com/

Javascript
01const magic = new Magic('YOUR_PUBLISHABLE_API_KEY', {
02  network: 'sepolia',
03});
04
05// Magic's node infrastructure maps 'mainnet' and 'sepolia' to 2 unique set of addresses.

#Custom Node

You can allow specific URLs to interact with the Magic SDK, such as a custom RPC URL to send transactions to your node. The Content Security Policy (CSP) of a browser dictates what resources can be loaded. If you're using a Dedicated Wallet, you can update the policy in the settings page of the dashboard with your custom URL. If you're using a Universal Wallet, please reach out to support to get your URL added.

important

The use of a custom node will require the RPC URL to the project's Content Security Policy from your Magic dashboard. Refer to the CSP documentation.

Javascript
01const customNodeOptions = {
02  rpcUrl: 'http://127.0.0.1:7545', // Your own node URL
03  chainId: 1011, // Your own node's chainId
04};
05
06// Setting network to localhost blockchain
07const magic = new Magic('YOUR_PUBLISHABLE_API_KEY', {
08  network: customNodeOptions,
09});
10
11// This configuration will map addresses in line with Magic's 'mainnet' setup.

#Common Methods

note

All Web.js examples are using [email protected] or later version.

#Send Transaction

#Ethers.js

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09const signer = await provider.getSigner();
10
11const destination = '0xE0cef4417a772512E6C95cEf366403839b0D6D6D';
12const amount = ethers.parseEther('1.0'); // Convert 1 ether to wei
13
14// Submit transaction to the blockchain
15const tx = await signer.sendTransaction({
16  to: destination,
17  value: amount,
18});
19
20// Wait for transaction to be mined
21const receipt = await tx.wait();

#Web3.js

Javascript
01import { Magic } from 'magic-sdk';
02import Web3 from 'web3';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09// Get user's Ethereum public address
10const fromAddress = (await web3.eth.getAccounts())[0];
11
12const destination = '0xE0cef4417a772512E6C95cEf366403839b0D6D6D';
13const amount = web3.utils.toWei(1); // Convert 1 ether to wei
14
15// Submit transaction to the blockchain and wait for it to be mined
16const receipt = await web3.eth.sendTransaction({
17  from: fromAddress,
18  to: destination,
19  value: amount,
20});

#Sign Message

#Ethers.js

Personal Sign

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09const signer = await provider.getSigner();
10
11const originalMessage = 'YOUR_MESSAGE';
12const signedMessage = await signer.signMessage(originalMessage);

Sign Typed Data v1

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09const signer = await provider.getSigner();
10
11// Get user's Ethereum public address
12const fromAddress = await signer.getAddress();
13
14const originalMessage = [
15  {
16    type: 'string',
17    name: 'fullName',
18    value: 'John Doe',
19  },
20  {
21    type: 'uint32',
22    name: 'userId',
23    value: '1234',
24  },
25];
26const params = [originalMessage, fromAddress];
27const method = 'eth_signTypedData';
28
29const signedMessage = await signer.provider.send(method, params);

Sign Typed Data v3

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09const signer = await provider.getSigner();
10
11// Get user's Ethereum public address
12const fromAddress = await signer.getAddress();
13
14const originalMessage = {
15  types: {
16    EIP712Domain: [
17      {
18        name: 'name',
19        type: 'string',
20      },
21      {
22        name: 'version',
23        type: 'string',
24      },
25      {
26        name: 'verifyingContract',
27        type: 'address',
28      },
29    ],
30    Greeting: [
31      {
32        name: 'contents',
33        type: 'string',
34     },
35    ],
36 },
37  primaryType: 'Greeting',
38  domain: {
39    name: 'Magic',
40    version: '1',
41    verifyingContract: '0xE0cef4417a772512E6C95cEf366403839b0D6D6D',
42  },
43  message: {
44    contents: 'Hello, from Magic!',
45  },
46};
47const params = [fromAddress, originalMessage];
48const method = 'eth_signTypedData_v3';
49
50const signedMessage = await signer.provider.send(method, params);

Sign Typed Data v4

Ethers (v6)
Ethers (v5)
01/*
02  Sign Typed Data v4 adds support for
03  arrays and recursive data types.
04  
05  Otherwise, it works the same as Sign Typed Data v3.
06 */
07
08import { Magic } from 'magic-sdk';
09import { ethers } from 'ethers';
10
11const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
12const provider = new ethers.BrowserProvider(magic.rpcProvider);
13
14// ⭐️ After user is successfully authenticated
15
16const signer = await provider.getSigner();
17
18// Get user's Ethereum public address
19const fromAddress = await signer.getAddress();
20
21const originalMessage = {
22  types: {
23    EIP712Domain: [
24      {
25        name: 'name',
26        type: 'string',
27      },
28      {
29        name: 'version',
30        type: 'string',
31      },
32      {
33        name: 'verifyingContract',
34        type: 'address',
35      },
36    ],
37    Greeting: [
38      {
39        name: 'contents',
40        type: 'string',
41      },
42    ],
43  },
44  primaryType: 'Greeting',
45  domain: {
46    name: 'Magic',
47    version: '1',
48    verifyingContract: '0xE0cef4417a772512E6C95cEf366403839b0D6D6D',
49  },
50  message: {
51    contents: 'Hello, from Magic!',
52  },
53};
54const params = [fromAddress, originalMessage];
55const method = 'eth_signTypedData_v4';
56
57const signedMessage = await signer.provider.send(method, params);

#Web3.js

Personal Sign

Typescript
01import { Magic } from 'magic-sdk';
02import Web3 from 'web3';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09// Get user's Ethereum public address
10const fromAddress = (await web3.eth.getAccounts())[0];
11
12const originalMessage = 'YOUR_MESSAGE';
13
14const signedMessage = await web3.eth.personal.sign(originalMessage, fromAddress);

Sign Typed Data v1

Typescript
01import { Magic } from 'magic-sdk';
02import Web3 from 'web3';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09// Get user's Ethereum public address
10const fromAddress = (await web3.eth.getAccounts())[0];
11
12const message = [
13  {
14    type: 'string',
15    name: 'fullName',
16    value: 'John Doe',
17  },
18  {
19    type: 'uint32',
20    name: 'userId',
21    value: '1234',
22  },
23];
24
25signedMessage = await web3.eth.signTypedData(fromAddress, message, true);

Sign Typed Data v4

Typescript
01/*
02  Sign Typed Data v4 adds support for
03  arrays and recursive data types.
04  
05  Otherwise, it works the same as Sign Typed Data v3.
06 */
07
08import { Magic } from 'magic-sdk';
09import Web3 from 'web3';
10
11const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
12const web3 = new Web3(magic.rpcProvider);
13
14// ⭐️ After user is successfully authenticated
15
16// Get user's Ethereum public address
17const fromAddress = (await web3.eth.getAccounts())[0];
18
19const message = {
20  types: {
21    EIP712Domain: [
22      {
23        name: 'name',
24        type: 'string',
25      },
26      {
27        name: 'version',
28        type: 'string',
29      },
30      {
31        name: 'verifyingContract',
32        type: 'address',
33      },
34    ],
35    Greeting: [
36      {
37        name: 'contents',
38        type: 'string',
39      },
40    ],
41  },
42  primaryType: 'Greeting',
43  domain: {
44    name: 'Magic',
45    version: '1',
46    verifyingContract: '0xE0cef4417a772512E6C95cEf366403839b0D6D6D',
47  },
48  message: {
49    contents: 'Hello, from Magic!',
50  },
51};
52
53const signedMessage = await web3.eth.signTypedData(fromAddress, message);

#Get Balance

#Ethers.js

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY')
05const provider = new ethers.BrowserProvider(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09const signer = await provider.getSigner();
10
11// Get user's Ethereum public address
12const address = await signer.getAddress();
13
14// Get user's balance in ether
15const balance = ethers.formatEther(
16  await provider.getBalance(address), // Balance is in wei
17);

#Web3.js

Javascript
01import { Magic } from 'magic-sdk';
02import Web3 from 'web3';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09// Get user's Ethereum public address
10const address = (await web3.eth.getAccounts())[0];
11
12// Get user's balance in ether
13const balance = web3.utils.fromWei(
14  await web3.eth.getBalance(address), // Balance is in wei
15);

#Smart Contract

In this example, we'll be demonstrating how to use Magic with ethers.js or web3.js to interact with Solidity smart contracts. The simple Hello World contract allows anyone to read and write a message to it.

Solidity
01pragma solidity ^0.5.10;
02
03contract HelloWorld {
04
05  string public message;
06
07  constructor(string memory initMessage) public {
08    message = initMessage;
09  }
10
11  function update(string memory newMessage) public {
12    message = newMessage;
13  }
14}

#Deploy Contract

#Ethers.js

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09const signer = await provider.getSigner();
10
11const contractABI =
12'[{"constant":false,"inputs":[{"name":"newMessage","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"message","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initMessage","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]';
13    
14const contractByteCode =
15 '0x608060405234801561001057600080fd5b5060405161047f38038061047f8339818101604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190505050806000908051906020019061009c9291906100a3565b5050610148565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610112565b82800160010185558215610112579182015b828111156101115782518255916020019190600101906100f6565b5b50905061011f9190610123565b5090565b61014591905b80821115610141576000816000905550600101610129565b5090565b90565b610328806101576000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c0100000000000000000000000000000000000000000000000000000000900480633d7403a314610058578063e21f37ce14610113575b600080fd5b6101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610196565b005b61011b6101b0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015b578082015181840152602081019050610140565b50505050905090810190601f1680156101885780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101ac92919061024e565b5050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102465780601f1061021b57610100808354040283529160200191610246565b820191906000526020600020905b81548152906001019060200180831161022957829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028f57805160ff19168380011785556102bd565b828001600101855582156102bd579182015b828111156102bc5782518255916020019190600101906102a1565b5b5090506102ca91906102ce565b5090565b6102f091905b808211156102ec5760008160009055506001016102d4565b5090565b9056fea265627a7a7230582003ae1ef5a63bf058bfd2b31398bdee39d3cbfbb7fbf84235f4bc2ec352ee810f64736f6c634300050a0032';
16const contractFactory = new ethers.ContractFactory(contractABI, contractByteCode, signer);
17
18// Deploy contract with "Hello World!" in the constructor
19const contract = await contractFactory.deploy('Hello World!');
20// Wait for deployment to finish
21const receipt = contract.deploymentTransaction()

#Web3.js

Javascript
01import { Magic } from 'magic-sdk';
02import Web3 from 'web3';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09// Get user's Ethereum public address
10const fromAddress = (await web3.eth.getAccounts())[0];
11
12const contractABI =
13  '[{"constant":false,"inputs":[{"name":"newMessage","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"message","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initMessage","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]';
14const contractByteCode =
15  '0x608060405234801561001057600080fd5b5060405161047f38038061047f8339818101604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190505050806000908051906020019061009c9291906100a3565b5050610148565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610112565b82800160010185558215610112579182015b828111156101115782518255916020019190600101906100f6565b5b50905061011f9190610123565b5090565b61014591905b80821115610141576000816000905550600101610129565b5090565b90565b610328806101576000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c0100000000000000000000000000000000000000000000000000000000900480633d7403a314610058578063e21f37ce14610113575b600080fd5b6101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610196565b005b61011b6101b0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015b578082015181840152602081019050610140565b50505050905090810190601f1680156101885780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101ac92919061024e565b5050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102465780601f1061021b57610100808354040283529160200191610246565b820191906000526020600020905b81548152906001019060200180831161022957829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028f57805160ff19168380011785556102bd565b828001600101855582156102bd579182015b828111156102bc5782518255916020019190600101906102a1565b5b5090506102ca91906102ce565b5090565b6102f091905b808211156102ec5760008160009055506001016102d4565b5090565b9056fea265627a7a7230582003ae1ef5a63bf058bfd2b31398bdee39d3cbfbb7fbf84235f4bc2ec352ee810f64736f6c634300050a0032';
16const contract = new web3.eth.Contract(JSON.parse(contractABI));
17
18// Deploy contract with "Hello World!" in the constructor and wait to finish
19const contractInstance = await contract
20  .deploy({
21    data: contractByteCode,
22    arguments: ['Hello World!'],
23  })
24  .send({
25    from: fromAddress,
26  });

#Read From Contract

#Ethers.js

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09const signer = await provider.getSigner();
10
11const contractABI =
12  '[{"constant":false,"inputs":[{"name":"newMessage","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"message","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initMessage","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]';
13const contractAddress = 'CONTRACT_ADDRESS';
14const contract = new ethers.Contract(contractAddress, contractABI, signer);
15
16// Read message from smart contract
17const message = await contract.message();

#Web3.js

Javascript
01import { Magic } from 'magic-sdk';
02import Web3 from 'web3';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09// Get user's Ethereum public address
10const fromAddress = (await web3.eth.getAccounts())[0];
11
12const contractABI =
13  '[{"constant":false,"inputs":[{"name":"newMessage","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"message","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initMessage","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]';
14const contractAddress = 'CONTRACT_ADDRESS';
15const contract = new web3.eth.Contract(JSON.parse(contractABI), contractAddress);
16
17// Read message from smart contract
18const message = await contract.methods.message().call();

#Write to Contract

#Ethers.js

Ethers (v6)
Ethers (v5)
01import { Magic } from 'magic-sdk';
02import { ethers } from 'ethers';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const provider = new ethers.BrowserProvider(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09const signer = await provider.getSigner();
10
11const contractABI =
12  '[{"constant":false,"inputs":[{"name":"newMessage","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"message","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initMessage","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]';
13const contractAddress = 'CONTRACT_ADDRESS';
14const contract = new ethers.Contract(contractAddress, contractABI, signer);
15
16// Send transaction to smart contract to update message
17const tx = await contract.update('NEW_MESSAGE');
18
19// Wait for transaction to finish
20const receipt = await tx.wait();

#Web3.js

Javascript
01import { Magic } from 'magic-sdk';
02import Web3 from 'web3';
03
04const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
05const web3 = new Web3(magic.rpcProvider);
06
07// ⭐️ After user is successfully authenticated
08
09// Get user's Ethereum public address
10const fromAddress = (await web3.eth.getAccounts())[0];
11
12const contractABI =
13  '[{"constant":false,"inputs":[{"name":"newMessage","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"message","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initMessage","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]';
14const contractAddress = 'CONTRACT_ADDRESS';
15const contract = new web3.eth.Contract(JSON.parse(contractABI), contractAddress);
16
17// Send transaction to smart contract to update message and wait to finish
18const receipt = await contract.methods.update('NEW_MESSAGE').send({ from: fromAddress });

#Resources