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

# How to Integrate with the Ethereum Blockchain using JavaScript

## Installation

To interact with the EVM network, you will need to use a web3 provider library, such as [`ethers.js`](https://docs.ethers.io/v5/getting-started/), with Magic.

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

### Ethers.js

<CodeGroup>
  ```bash NPM icon="npm" theme={null}
  npm install ethers magic-sdk
  ```

  ```bash Yarn icon="yarn" theme={null}
  yarn add ethers magic-sdk
  ```

  ```javascript CDN icon="code" theme={null}
  <script src="https://cdn.ethers.io/scripts/ethers-v4.min.js"></script>
  ```
</CodeGroup>

## Initialization

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

<Info>
  **Important**

  Ethereum provider is only supported in **magic-sdk\@1.0.1 or later** versions.
</Info>

### Ethers.js

**ES Modules/TypeScript**

<CodeGroup key="ethers-es-modules">
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from "magic-sdk";
  import { ethers } from "ethers";

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);
  ```
</CodeGroup>

**CommonJS**

<CodeGroup key="ethers-commonjs">
  ```javascript Ethers (v6) icon="square-js" theme={null}
  const { Magic } = require('magic-sdk');
  const ethers = require('ethers');

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  const { Magic } = require('magic-sdk');
  const ethers = require('ethers');

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);
  ```
</CodeGroup>

### Mainnet

Mainnet Block Explorer: [https://etherscan.io](https://etherscan.io)

```javascript JavaScript icon="square-js" theme={null}
const magic = new Magic('YOUR_PUBLISHABLE_API_KEY', {
  network: 'mainnet',
});

// Magic's node infrastructure maps 'mainnet' and 'testnet' to 2 unique set of addresses.
```

### Testnet

Sepolia Block Explorer: [https://sepolia.etherscan.io/](https://sepolia.etherscan.io/)

Sepolia Testnet Faucet: [https://sepoliafaucet.com/](https://sepoliafaucet.com/)

```javascript JavaScript icon="square-js" theme={null}
const magic = new Magic('YOUR_PUBLISHABLE_API_KEY', {
  network: 'sepolia',
});

// 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. You can update the policy in the settings page of the [dashboard](https://dashboard.magic.link) with your custom URL.

<Info>
  **Important**

  The use of a custom node will require the RPC URL to the project's Content Security Policy from your [Magic Dashboard](https://dashboard.magic.link). Refer to the [CSP documentation](/embedded-wallets/wallets/security/content-security-policy).
</Info>

```javascript JavaScript icon="square-js" theme={null}
const customNodeOptions = {
  rpcUrl: 'http://127.0.0.1:7545', // Your own node URL
  chainId: 1011, // Your own node's chainId
};

// Setting network to localhost blockchain
const magic = new Magic('YOUR_PUBLISHABLE_API_KEY', {
  network: customNodeOptions,
});

// This configuration will map addresses in line with Magic's 'mainnet' setup.
```

## Common Methods

<Note>
  **Note**

  All Web.js examples are using **web3\@1.2.0** or later version.
</Note>

## Send Transaction

### Ethers.js

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  const destination = '0xE0cef4417a772512E6C95cEf366403839b0D6D6D';
  const amount = ethers.parseEther('1.0'); // Convert 1 ether to wei

  // Submit transaction to the blockchain
  const tx = await signer.sendTransaction({
    to: destination,
    value: amount,
  });

  // Wait for transaction to be mined
  const receipt = await tx.wait();
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  const destination = '0xE0cef4417a772512E6C95cEf366403839b0D6D6D';
  const amount = ethers.utils.parseEther('1.0'); // Convert 1 ether to wei

  // Submit transaction to the blockchain
  const tx = await signer.sendTransaction({
  to: destination,
  value: amount,
  });

  // Wait for transaction to be mined
  const receipt = await tx.wait();
  ```
</CodeGroup>

## Sign Message

### Ethers.js

#### Personal Sign

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  const originalMessage = 'YOUR_MESSAGE';
  const signedMessage = await signer.signMessage(originalMessage);
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);
  await provider.send('eth_requestAccounts', []);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  const originalMessage = 'YOUR_MESSAGE';
  const signedMessage = await signer.signMessage(originalMessage);
  ```
</CodeGroup>

#### Sign Typed Data v1

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  // Get user's Ethereum public address
  const fromAddress = await signer.getAddress();

  const originalMessage = [
    {
      type: 'string',
      name: 'fullName',
      value: 'John Doe',
    },
    {
      type: 'uint32',
      name: 'userId',
      value: '1234',
    },
  ];

  const params = [originalMessage, fromAddress];
  const method = 'eth_signTypedData';

  const signedMessage = await signer.provider.send(method, params);
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic?.rpcProvider);
  await provider.send('eth_requestAccounts', []);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  // Get user's Ethereum public address
  const fromAddress = await signer.getAddress();

  const originalMessage = [
    {
      type: 'string',
      name: 'fullName',
      value: 'John Doe',
    },
    {
      type: 'uint32',
      name: 'userId',
      value: '1234',
    },
  ];
  const params = [originalMessage, fromAddress];
  const method = 'eth_signTypedData';

  const signedMessage = await signer.provider.send(method, params);
  ```
</CodeGroup>

#### Sign Typed Data v3

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  // Get user's Ethereum public address
  const fromAddress = await signer.getAddress();

  const originalMessage = {
    types: {
      EIP712Domain: [
        {
          name: 'name',
          type: 'string',
        },
        {
          name: 'version',
          type: 'string',
        },
        {
          name: 'verifyingContract',
          type: 'address',
        },
      ],
      Greeting: [
        {
          name: 'contents',
          type: 'string',
        },
      ],
    },
    primaryType: 'Greeting',
    domain: {
      name: 'Magic',
      version: '1',
      verifyingContract: '0xE0cef4417a772512E6C95cEf366403839b0D6D6D',
    },
    message: {
      contents: 'Hello, from Magic!',
    },
  };

  const params = [fromAddress, originalMessage];
  const method = 'eth_signTypedData_v3';

  const signedMessage = await signer.provider.send(method, params);
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic?.rpcProvider);
  await provider.send('eth_requestAccounts', []);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  // Get user's Ethereum public address
  const fromAddress = await signer.getAddress();

  const originalMessage = {
    types: {
      EIP712Domain: [
        {
          name: 'name',
          type: 'string',
        },
        {
          name: 'version',
          type: 'string',
        },
        {
          name: 'verifyingContract',
          type: 'address',
        },
      ],
      Greeting: [
        {
          name: 'contents',
          type: 'string',
       },
      ],
   },
    primaryType: 'Greeting',
    domain: {
      name: 'Magic',
      version: '1',
      verifyingContract: '0xE0cef4417a772512E6C95cEf366403839b0D6D6D',
    },
    message: {
      contents: 'Hello, from Magic!',
    },
  };
  const params = [fromAddress, originalMessage];
  const method = 'eth_signTypedData_v3';

  const signedMessage = await signer.provider.send(method, params);
  ```
</CodeGroup>

#### Sign Typed Data v4

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  /*
    Sign Typed Data v4 adds support for
    arrays and recursive data types.

  Otherwise, it works the same as Sign Typed Data v3.
  \*/

  import { Magic } from "magic-sdk";
  import { ethers } from "ethers";

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  // Get user's Ethereum public address
  const fromAddress = await signer.getAddress();

  const originalMessage = {
    types: {
      EIP712Domain: [
        {
          name: 'name',
          type: 'string',
        },
        {
          name: 'version',
          type: 'string',
        },
        {
          name: 'verifyingContract',
          type: 'address',
        },
      ],
      Greeting: [
        {
          name: 'contents',
          type: 'string',
        },
      ],
    },
    primaryType: 'Greeting',
    domain: {
      name: 'Magic',
      version: '1',
      verifyingContract: '0xE0cef4417a772512E6C95cEf366403839b0D6D6D',
    },
    message: {
      contents: 'Hello, from Magic!',
    },
  };
  const params = [fromAddress, originalMessage];
  const method = 'eth_signTypedData_v4';

  const signedMessage = await signer.provider.send(method, params);
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  /*
    Sign Typed Data v4 adds support for
    arrays and recursive data types.

    Otherwise, it works the same as Sign Typed Data v3.
   */

  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  // Get user's Ethereum public address
  const fromAddress = await signer.getAddress();

  const originalMessage = {
    types: {
      EIP712Domain: [
        {
          name: 'name',
          type: 'string',
        },
        {
          name: 'version',
          type: 'string',
        },
        {
          name: 'verifyingContract',
          type: 'address',
        },
      ],
      Greeting: [
        {
          name: 'contents',
          type: 'string',
        },
      ],
    },
    primaryType: 'Greeting',
    domain: {
      name: 'Magic',
      version: '1',
      verifyingContract: '0xE0cef4417a772512E6C95cEf366403839b0D6D6D',
    },
    message: {
      contents: 'Hello, from Magic!',
    },
  };
  const params = [fromAddress, originalMessage];
  const method = 'eth_signTypedData_v4';

  const signedMessage = await signer.provider.send(method, params);
  ```
</CodeGroup>

## Get Balance

### Ethers.js

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY')
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  // Get user's Ethereum public address
  const address = await signer.getAddress();

  // Get user's balance in ether
  const balance = ethers.formatEther(
    await provider.getBalance(address), // Balance is in wei
  );
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);
  await provider.send('eth_requestAccounts', []);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  // Get user's Ethereum public address
  const address = await signer.getAddress();

  // Get user's balance in ether
  const balance = ethers.utils.formatEther(
  await provider.getBalance(address), // Balance is in wei
  );
  ```
</CodeGroup>

## Smart Contract

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

```solidity Solidity icon="ethereum" theme={null}
pragma solidity ^0.5.10;

contract HelloWorld {
  string public message;

  constructor(string memory initMessage) public {
    message = initMessage;
  }

  function update(string memory newMessage) public {
    message = newMessage;
  }
}
```

## Deploy Contract

### Ethers.js

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  const contractABI =
  '[{"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"}]';

  const contractByteCode =
   '0x608060405234801561001057600080fd5b5060405161047f38038061047f8339818101604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190505050806000908051906020019061009c9291906100a3565b5050610148565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610112565b82800160010185558215610112579182015b828111156101115782518255916020019190600101906100f6565b5b50905061011f9190610123565b5090565b61014591905b80821115610141576000816000905550600101610129565b5090565b90565b610328806101576000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c0100000000000000000000000000000000000000000000000000000000900480633d7403a314610058578063e21f37ce14610113575b600080fd5b6101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610196565b005b61011b6101b0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015b578082015181840152602081019050610140565b50505050905090810190601f1680156101885780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101ac92919061024e565b5050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102465780601f1061021b57610100808354040283529160200191610246565b820191906000526020600020905b81548152906001019060200180831161022957829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028f57805160ff19168380011785556102bd565b828001600101855582156102bd579182015b828111156102bc5782518255916020019190600101906102a1565b5b5090506102ca91906102ce565b5090565b6102f091905b808211156102ec5760008160009055506001016102d4565b5090565b9056fea265627a7a7230582003ae1ef5a63bf058bfd2b31398bdee39d3cbfbb7fbf84235f4bc2ec352ee810f64736f6c634300050a0032';
  const contractFactory = new ethers.ContractFactory(contractABI, contractByteCode, signer);

  // Deploy contract with "Hello World!" in the constructor
  const contract = await contractFactory.deploy('Hello World!');
  // Wait for deployment to finish
  const receipt = contract.deploymentTransaction()
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);
  await provider.send('eth_requestAccounts', []);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  // ⭐️ After user is successfully authenticated
  const contractABI =
  '[{"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"}]';

  const contractByteCode =
  '0x608060405234801561001057600080fd5b5060405161047f38038061047f8339818101604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190505050806000908051906020019061009c9291906100a3565b5050610148565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610112565b82800160010185558215610112579182015b828111156101115782518255916020019190600101906100f6565b5b50905061011f9190610123565b5090565b61014591905b80821115610141576000816000905550600101610129565b5090565b90565b610328806101576000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c0100000000000000000000000000000000000000000000000000000000900480633d7403a314610058578063e21f37ce14610113575b600080fd5b6101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610196565b005b61011b6101b0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015b578082015181840152602081019050610140565b50505050905090810190601f1680156101885780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101ac92919061024e565b5050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102465780601f1061021b57610100808354040283529160200191610246565b820191906000526020600020905b81548152906001019060200180831161022957829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028f57805160ff19168380011785556102bd565b828001600101855582156102bd579182015b828111156102bc5782518255916020019190600101906102a1565b5b5090506102ca91906102ce565b5090565b6102f091905b808211156102ec5760008160009055506001016102d4565b5090565b9056fea265627a7a7230582003ae1ef5a63bf058bfd2b31398bdee39d3cbfbb7fbf84235f4bc2ec352ee810f64736f6c634300050a0032';
  const contractFactory = new ethers.ContractFactory(contractABI, contractByteCode, signer);

  // Deploy contract with "Hello World!" in the constructor
  const contract = await contractFactory.deploy('Hello World!');

  // Wait for deployment to finish
  const receipt = await contract.deployed();
  ```
</CodeGroup>

## Read From Contract

### Ethers.js

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  const contractABI =
  '[{"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"}]';
  const contractAddress = 'CONTRACT_ADDRESS';
  const contract = new ethers.Contract(contractAddress, contractABI, signer);

  // Read message from smart contract
  const message = await contract.message();
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);
  await provider.send('eth_requestAccounts', []);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  const contractABI =
    '[{"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"}]';
  const contractAddress = 'CONTRACT_ADDRESS';
  const contract = new ethers.Contract(contractAddress, contractABI, signer);

  // Read message from smart contract
  const message = await contract.message();
  ```
</CodeGroup>

## Write to Contract

### Ethers.js

<CodeGroup>
  ```javascript Ethers (v6) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.BrowserProvider(magic.rpcProvider);

  // ⭐️ After user is successfully authenticated

  const signer = await provider.getSigner();

  const contractABI =
    '[{"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"}]';
  const contractAddress = 'CONTRACT_ADDRESS';
  const contract = new ethers.Contract(contractAddress, contractABI, signer);

  // Send transaction to smart contract to update message
  const tx = await contract.update('NEW_MESSAGE');

  // Wait for transaction to finish
  const receipt = await tx.wait();
  ```

  ```javascript Ethers (v5) icon="square-js" theme={null}
  import { Magic } from 'magic-sdk';
  import { ethers } from 'ethers';

  const magic = new Magic('YOUR_PUBLISHABLE_API_KEY');
  const provider = new ethers.providers.Web3Provider(magic.rpcProvider);
  await provider.send('eth_requestAccounts', []);

  // ⭐️ After user is successfully authenticated

  const signer = provider.getSigner();

  const contractABI =
  '[{"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"}]';
  const contractAddress = 'CONTRACT_ADDRESS';
  const contract = new ethers.Contract(contractAddress, contractABI, signer);

  // Send transaction to smart contract to update message
  const tx = await contract.update('NEW_MESSAGE');

  // Wait for transaction to finish
  const receipt = await tx.wait();
  ```
</CodeGroup>

## Resources

* [Magic JavaScript SDK](https://github.com/magiclabs/magic-js)
* [Ethers.js JavaScript example](https://go.magic.link/example-ethers)
