Ethereum

JavaScript

Installation

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

note

If you are already familiar with Ethereum application development, you can skip straight to our kitchen sink examples:

👉 Ethers.js Example
👉 Web3.js Example

Ethers.js

npm install --save ethers

Web3.js

npm install --save web3

Initializing Provider

important

Ethereum provider is only supported in magic-sdk@1.0.1 or later versions.

Ethers.js

import { Magic } from 'magic-sdk';
import { ethers } from 'ethers';
// Test key defaults to "rinkeby", live key defaults to "mainnet"
const magic = new Magic("YOUR_PUBLISHABLE_API_KEY");
const provider = new ethers.providers.Web3Provider(magic.rpcProvider);

Web3.js

import { Magic } from 'magic-sdk';
import Web3 from 'web3';
// Test key defaults to "rinkeby", live key defaults to "mainnet"
const magic = new Magic("YOUR_PUBLISHABLE_API_KEY");
const web3 = new Web3(magic.rpcProvider); // Or window.web3 = ...

Use Different Networks

Choose Different Testnet

const magic = new Magic("YOUR_PUBLISHABLE_API_KEY", {
network: "ropsten" // Supports "rinkeby", "ropsten", "kovan"
});

Configure Custom Nodes

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 });

Get User Info

Ethers.js

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 address = await signer.getAddress();
// Get user's balance in ether
const balance = ethers.utils.formatEther(
await provider.getBalance(userAddress) // Balance is in wei
);

Web3.js

note

Example is using web3@1.2.0 or later version.

import { Magic } from "magic-sdk";
import Web3 from "web3";
const magic = new Magic("YOUR_PUBLISHABLE_API_KEY");
const web3 = new Web3(magic.rpcProvider);
// ⭐️ After user is successfully authenticated
// Get user's Ethereum public address
const address = (await web3.eth.getAccounts())[0];
// Get user's balance in ether
const balance = web3.utils.fromWei(
await web3.eth.getBalance(address) // Balance is in wei
);

Send Transaction

Ethers.js

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();

Web3.js

note

Example is using web3@1.2.0 or later version.

import { Magic } from 'magic-sdk';
import Web3 from 'web3';
const magic = new Magic("YOUR_PUBLISHABLE_API_KEY");
const web3 = new Web3(magic.rpcProvider);
// ⭐️ After user is successfully authenticated
// Get user's Ethereum public address
const fromAddress = (await web3.eth.getAccounts())[0];
const destination = "0xE0cef4417a772512E6C95cEf366403839b0D6D6D";
const amount = web3.utils.toWei(1); // Convert 1 ether to wei
// Submit transaction to the blockchain and wait for it to be mined
const receipt = await web3.eth.sendTransaction({
from: fromAddress,
to: destination,
value: amount
})

Sign Message

Ethers.js

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 originalMessage = "YOUR_MESSAGE";
const signedMessage = await signer.signMessage(originalMessage);

Web3.js

note

The following examples assume web3@>=1.2.0

import { Magic } from "magic-sdk";
import Web3 from "web3";
const magic = new Magic("YOUR_PUBLISHABLE_API_KEY");
const web3 = new Web3(magic.rpcProvider);
// ⭐️ After user is successfully authenticated
// Get user's Ethereum public address
const fromAddress = (await web3.eth.getAccounts())[0];
const originalMessage = "YOUR_MESSAGE";
const signedMessage = await web3.eth.personal.sign(
originalMessage,
fromAddress
);

Smart Contract

Solidity 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.

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;
}
}

Ethers.js

Deploy Contract
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 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();
Read From Contract
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 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 = "0x8b211dfebf490a648f6de859dfbed61fa22f35e0";
const contract = new ethers.Contract(
contractAddress,
contractABI,
signer
);
// Read message from smart contract
const message = await contract.message();
Write to Contract
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 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 = "0x8b211dfebf490a648f6de859dfbed61fa22f35e0";
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();

Web3.js

note

Example is using web3@1.2.0 or later version.

Deploy Contract
import { Magic } from "magic-sdk";
import Web3 from "web3";
const magic = new Magic("YOUR_PUBLISHABLE_API_KEY");
const web3 = new Web3(magic.rpcProvider);
// ⭐️ After user is successfully authenticated
// Get user's Ethereum public address
const fromAddress = (await web3.eth.getAccounts())[0];
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 contract = new web3.eth.Contract(JSON.parse(contractABI));
// Deploy contract with "Hello World!" in the constructor and wait to finish
const contractInstance = await contract
.deploy({
data: contractByteCode,
arguments: ["Hello World!"]
})
.send({
from: fromAddress
});
Read From Contract
import { Magic } from "magic-sdk";
import Web3 from "web3";
const magic = new Magic("YOUR_PUBLISHABLE_API_KEY");
const web3 = new Web3(magic.rpcProvider);
// ⭐️ After user is successfully authenticated
// Get user's Ethereum public address
const fromAddress = (await web3.eth.getAccounts())[0];
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 = "0x8b211dfebf490a648f6de859dfbed61fa22f35e0";
const contract = new web3.eth.Contract(JSON.parse(contractABI), contractAddress);
// Read message from smart contract
const message = await contract.methods.message().call();
Write to Contract
import { Magic } from "magic-sdk";
import Web3 from "web3";
const magic = new Magic("YOUR_PUBLISHABLE_API_KEY");
const web3 = new Web3(magic.rpcProvider);
// ⭐️ After user is successfully authenticated
// Get user's Ethereum public address
const fromAddress = (await web3.eth.getAccounts())[0];
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 = "0x8b211dfebf490a648f6de859dfbed61fa22f35e0";
const contract = new web3.eth.Contract(JSON.parse(contractABI), contractAddress);
// Send transaction to smart contract to update message and wait to finish
const receipt = await contract.methods
.update("NEW_MESSAGE")
.send({ from: fromAddress });

iOS

Installation

To interact with the Ethereum blockchain, Magic iOS SDK embeds Web3.swift as sub dependency. No more extra dependency is needed.

Initializing Provider

note

Following example is using Swift 5 with XCode 11. IOS demo will be open-sourced soon.

// AppDelegate.swift
import MagicSDK
import UIKit
@UIApplicationMain
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// assign the newly created Magic instance to shared property
// Test key defaults to "rinkeby", live key defaults to "mainnet"
Magic.shared = Magic("YOUR_PUBLISHABLE_API_KEY");
return true
}
// ViewController.swift
import UIKit
import MagicSDK
import Web3
class Web3ViewController: UIViewController {
let web3 = Web3(provider: Magic.shared.rpcProvider)
}

Use Different Networks

Choose Different Testnet

// AppDelegate.swift
import MagicSDK
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// assign to Magic singleton
Magic.shared = Magic("YOUR_PUBLISHABLE_API_KEY", EthNetwork.rinkeby);
return true
}

Configure Custom Nodes

// AppDelegate.swift
import MagicSDK
// assign to Magic singleton
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let config = CustomNodeConfiguration(rpcUrl: "https://alchemy.io", chainId: 1)
Magic.shared = Magic(apiKey: "API_KEY", customNode: config);
return true
}
important

Do not set the custom nodes to local IP address (E.x. "http://127.0.0.1"). Local IP will point to the network environment inside mobile device / simulator

Associated Class

CustomNodeConfiguration(rpcUrl: String, chainId: Int?)

  • rpcUrl :Your own node URL
  • chainId : Your own node's chainId

EthNetwork

public enum EthNetwork: String {
case mainnet
case kovan
case rinkeby
case ropsten
}

Get User Info

import MagicSDK
import Web3
import PromiseKit
class Web3ViewController: UIViewController {
var web3 = Web3(provider: Magic.shared.rpcProvider)
// ⭐️ After user is successfully authenticated
@IBOutlet weak var accountLabel: UILabel!
func getAccount() {
firstly {
// Get user's Ethereum public address
web3.eth.accounts()
}.done { accounts -> Void in
if let account = accounts.first {
// Set to UILa
self.accountLabel.text = account.hex(eip55: false)
} else {
print("No Account Found")
}
}.catch { error in
print("Error loading accounts and balance: \(error)")
}
}
}

Send Transaction

import MagicSDK
import Web3
class Web3ViewController: UIViewController {
var web3 = Web3(provider: Magic.shared.rpcProvider)
var account: EthereumAddress?
// ⭐️ After user is successfully authenticated
func sendTransaction() {
guard let account = self.account else { return }
// Construct a transaction
let transaction = EthereumTransaction(
from: account, // from Get User Info section
to: EthereumAddress(hexString: "0xE0cef4417a772512E6C95cEf366403839b0D6D6D"),
value: EthereumQuantity(quantity: 1.gwei)
)
// Submit transaction to the blockchain
web3.eth.sendTransaction(transaction: transaction).done { (transactionHash) in
print(transactionHash.hex())
}.catch { error in
print(error.localizedDescription)
}
}
}

Sign Message

Magic iOS SDK extends the functionality from Web3.swift to allow developers to sign Typed Data. Make sure to import MagicSDK while using these functions.

import MagicSDK
import Web3
import PromiseKit
class ViewController: UIViewController {
let web3 = Web3(provider: Magic.shared.rpcProvider)
var account: EthereumAddress?
func ethSign() {
guard let account = self.account else { return }
let message = try! EthereumData("Hello World".data(using: .utf8)!)
web3.eth.sign(from: account, message: message).done({ result in
print(result.hex())
})
}
}

Smart Contract

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

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

import MagicSDK
import Web3
class Web3ViewController: UIViewController {
let web3 = Web3(provider: Magic.shared.rpcProvider)
var account: EthereumAddress?
// ⭐️ After user is successfully authenticated
func deployContract() {
guard let account = self.account else { return }
do {
let 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"}]
""".data(using: .utf8)!
let contractByteCode = try EthereumData("0x608060405234801561001057600080fd5b5060405161047f38038061047f8339818101604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190505050806000908051906020019061009c9291906100a3565b5050610148565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610112565b82800160010185558215610112579182015b828111156101115782518255916020019190600101906100f6565b5b50905061011f9190610123565b5090565b61014591905b80821115610141576000816000905550600101610129565b5090565b90565b610328806101576000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c0100000000000000000000000000000000000000000000000000000000900480633d7403a314610058578063e21f37ce14610113575b600080fd5b6101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610196565b005b61011b6101b0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015b578082015181840152602081019050610140565b50505050905090810190601f1680156101885780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101ac92919061024e565b5050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102465780601f1061021b57610100808354040283529160200191610246565b820191906000526020600020905b81548152906001019060200180831161022957829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028f57805160ff19168380011785556102bd565b828001600101855582156102bd579182015b828111156102bc5782518255916020019190600101906102a1565b5b5090506102ca91906102ce565b5090565b6102f091905b808211156102ec5760008160009055506001016102d4565b5090565b9056fea265627a7a7230582003ae1ef5a63bf058bfd2b31398bdee39d3cbfbb7fbf84235f4bc2ec352ee810f64736f6c634300050a0032")
/// Create Contract instance
let contract = try web3.eth.Contract(json: contractABI, abiKey: nil, address: nil)
/// Deploy contract
guard let invocation = contract.deploy(byteCode: contractByteCode) else { return }
invocation.send(from: self.account!, gas: 1025256, gasPrice: 0) { (hash, error) in
print(hash?.hex() ?? "Missing Hash")
print(error?.localizedDescription ?? "Error")
}
} catch {
print(error.localizedDescription)
}
}
}

Read From Contract

import MagicSDK
import Web3
class MagicViewController: UIViewController {
let web3 = Web3(provider: Magic.shared.rpcProvider)
var account: EthereumAddress?
// ⭐️ After user is successfully authenticated
func getMessage() {
do {
/// Construct contract instance
let 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"}]
""".data(using: .utf8)!
let contract = try web3.eth.Contract(json: contractABI, abiKey: nil, address: EthereumAddress(ethereumValue: "0x8b211dfebf490a648f6de859dfbed61fa22f35e0"))
/// contract call
contract["message"]?().call() { response, error in
if let response = response, let message = response[""] as? String {
print(message.description)
} else {
print(error?.localizedDescription ?? "Failed to get response")
}
}
} catch {
/// Error handling
print(error.localizedDescription)
}
}
}

Write to Contract

import MagicSDK
import Web3
class MagicViewController: UIViewController {
let web3 = Web3(provider: Magic.shared.rpcProvider)
var account: EthereumAddress?
// ⭐️ After user is successfully authenticated
func writeMessage() {
guard let account = self.account else { return }
do {
/// contract instance
let 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"}]
""".data(using: .utf8)!
let contract = try web3.eth.Contract(json: contractABI, abiKey: nil, address: EthereumAddress(ethereumValue: "0x8b211dfebf490a648f6de859dfbed61fa22f35e0"))
/// contract call
guard let transaction = contract["update"]?("NEW_MESSAGE").createTransaction(
nonce: 0,
from: account,
value: 0,
gas: EthereumQuantity(150000),
gasPrice: EthereumQuantity(quantity: 21.gwei)
) else { return }
web3.eth.sendTransaction(transaction: transaction).done({ txHash in
print(txHash.hex())
}).catch{ error in
print(error.localizedDescription)
}
} catch {
print(error.localizedDescription)
}
}
}

Android

Installation

To interact with the Ethereum blockchain, Magic Android SDK integrates Web3j as sub dependency.

Add the following dependencies in build.gradle

dependencies {
implementation 'link.magic:magic-android:0.3.0'
implementation 'org.web3j:core:4.6.0-android' // Not required
implementation 'org.web3j:geth:4.6.0-android' // Only for personal Sign
}

Initializing Provider

note

The following example is using Kotlin 1.3. Android demo will be open-sourced soon. You may use Android Studio to convert Java to Kotlin or vice versa.

class MagicActivity: AppCompatActivity() {
lateinit var magic: Magic
lateinit var web3j: Web3j
lateinit var gethWeb3j: Geth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
magic = Magic(this, "YOUR_PUBLISHABLE_API_KEY")
web3j = Web3j.build(magic.rpcProvider)
gethWeb3j = Geth.build(magic.rpcProvider)
}
}

Use Different Networks

Choose Different Testnet

magic = Magic(this, "YOUR_PUBLISHABLE_API_KEY", Magic.Network.Mainnet)

Configure Custom Nodes

magic = Magic(this, "##YOUR_PUBLISHABLE_API_KEY", CustomNodeConfiguration("https://alchemy.io"))
important

Do not set the custom nodes to local IP address (E.x. "http://127.0.0.1"\), because local IP will point to the network environment inside mobile device / simulator. Try accessible IP address in the same Wifi/Internet Environment (E.x. "http://10.0.0.93:3000"\)

Associated Class

CustomNodeConfiguration(rpcUrl: String, chainId: Int?)

  • rpcUrl :Your own node URL
  • chainId : Your own node's chainId

Magic.EthNetwork

enum class EthNetwork {
Mainnet, Kovan, Rinkeby, Ropsten
}

Get User Info

class MagicActivity: AppCompatActivity() {
lateinit var magic: Magic
lateinit var web3j: Web3j
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
magic = Magic(this, "YOUR_PUBLISHABLE_API_KEY")
web3j = Web3j.build(magic.rpcProvider)
}
// ⭐️ After user is successfully authenticated
fun getAccount(){
try {
val accounts = web3j.ethAccounts().sendAsync()
accounts.whenComplete { accRepsonse: EthAccounts?, error: Throwable? ->
if (error != null) {
Log.e("MagicError", error.localizedMessage)
}
if (accRepsonse != null && !accRepsonse.hasError()) {
account = accRepsonse.accounts[0]
Log.d("Magic", "Your address is $account")
}
}
} catch (e: Exception) {
Log.e("Error", e.localizedMessage)
}
}
}

Send Transaction

class MagicActivity: AppCompatActivity() {
lateinit var magic: Magic
lateinit var web3j: Web3j
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
magic = Magic(this, "YOUR_PUBLISHABLE_API_KEY")
web3j = Web3j.build(magic.rpcProvider)
}
// ⭐️ After user is successfully authenticated
fun sendTransaction(v: View) {
try {
val value: BigInteger = Convert.toWei("0.5", Convert.Unit.ETHER).toBigInteger()
val transaction = createEtherTransaction(account, BigInteger("1"), BigInteger("21000"), BigInteger("21000"), account, value)
val receipt = web3j.ethSendTransaction(transaction).send()
Log.d("Transaction complete: " + receipt.transactionHash)
} catch (e: Exception) {
Log.e("Error", e.localizedMessage)
}
}
}

Sign Message

Magic Android SDK extends the functionality from Web3j to allow developers to sign Typed Data. You may find it in magic.web3jSigExt

class MagicActivity: AppCompatActivity() {
lateinit var magic: Magic
lateinit var web3j: Web3j
lateinit var gethWeb3j: Geth
// ⭐️ After user is successfully authenticated
private var account: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
magic = Magic(this, "YOUR_PUBLISHABLE_API_KEY")
web3j = Web3j.build(magic.rpcProvider)
gethWeb3j = Geth.build(magic.rpcProvider)
}
fun personSign(view: View) {
val message = "Hello from Magic!!!"
val personalSign: PersonalSign = gethWeb3j.personalSign(
message, account, "password")
.send()
Log.d("Magic", "Signed Message: " + personalSign.signedMessage)
// Recover Message
val recovered = gethWeb3j.personalEcRecover(message, personalSign.signedMessage).send()
Log.d("Magic", "Recovered Address: " + recovered.recoverAccountId)
}
}

Smart Contract

Solidity Contract

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

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;
}
}
Create a Kotlin/Java Contract Class from ABI

Web3j supports the auto-generation of smart contract function wrappers in Java from Solidity ABI files.

To get started, you must have two files

  • ABI JSON file <Contract>.json
  • ByteCode file <Contract>.bin
Install web3j cli-tool
$ curl -L https://get.web3j.io | sh

You may need to install a JDK to support this library

After it has been installed to your computer, you may run the following command to check

$ web3j version
Create the contract class
$ web3j solidity generate -a=./path/to/<Contract>.json -b=./path/to/<Contract>.bin -o=/output/path/ -p={packageName}

You’ll find a Contract.java file created in your output directory above. Put this file in your project, and no more changes are needed.

For more detail about this section. Please check the following link
https://web3j.readthedocs.io/en/latest/smart_contracts.html#solidity-smart-contract-wrappers

Contract Functions

When deploying contract or building contract using web3j library, Magic offers MagicTxnManager class as a default TransactionManager that helps you to avoid dealing with private keys or credentials that Contract class requires.

Deploy Contract
import link.magic.demo.contract.Contract // This is the contract class you created above
class MagicActivity: AppCompatActivity() {
lateinit var magic: Magic
lateinit var web3j: Web3j
// ⭐️ After user is successfully authenticated
private var account: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
magic = Magic(this, "YOUR_PUBLISHABLE_API_KEY")
web3j = Web3j.build(magic.rpcProvider)
}
fun deployContract(view: View) {
try {
val price = BigInteger.valueOf(22000000000L)
val limit = BigInteger.valueOf(4300000)
val gasProvider = StaticGasProvider(price, limit)
val contract = Contract.deploy(
web3j,
account?.let { MagicTxnManager(web3j, it) },
gasProvider,
"HELLO_WORLD_FROM_ANDROID"
).send()
Log.d("Magic", "Deploy to" + contract.contractAddress)
} catch (e: Exception) {
Log.e("E", "error", e)
}
}
}
Read From Contract
fun contractRead(view: View) {
try {
val price = BigInteger.valueOf(22000000000L)
val limit = BigInteger.valueOf(4300000)
val gasProvider = StaticGasProvider(price, limit)
// Contract in Rinkeby testnet
val contract = ExampleContract.load("0x6a2d321a3679b1b3c8a19b84e41abd11763a8ab5", web3j, account?.let { MagicTxnManager(web3j, it) }, gasProvider)
if (contract.isValid) {
val ethCall = contract.message().send()
Log.d("Magic", ethCall.toString())
} else {
throw Error("contract not valid")
}
} catch (e: Exception) {
Log.e("E", "error", e)
}
}
Write to Contract
fun contractWrite(view: View) {
try {
val price = BigInteger.valueOf(22000000000L)
val limit = BigInteger.valueOf(4300000)
val gasProvider = StaticGasProvider(price, limit)
// Contract in Rinkeby testnet
val contract = ExampleContract.load("0x6a2d321a3679b1b3c8a19b84e41abd11763a8ab5", web3j, account?.let { MagicTxnManager(web3j, it) }, gasProvider)
if (contract.isValid) {
val ethCall = contract.update("NEW_MESSAGE_FROM_ANDROID").send()
Log.d("Magic", ethCall.toString())
} else {
throw Error("contract not valid")
}
} catch (e: Exception) {
Log.e("E", "error", e)
}
}