├── .watchmanconfig ├── assets ├── icon.png └── splash.png ├── .gitignore ├── babel.config.js ├── rn-cli.config.js ├── src ├── lib │ └── ethereum │ │ ├── network.ts │ │ ├── wallet.ts │ │ ├── assets.ts │ │ └── contracts │ │ └── erc20.ts └── components │ ├── EthereumProvider.tsx │ └── Wallet.tsx ├── App.tsx ├── global.js ├── tsconfig.json ├── app.json ├── shim.js ├── README.md └── package.json /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrillCyborg/expo-eth-wallet/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrillCyborg/expo-eth-wallet/HEAD/assets/splash.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p12 6 | *.key 7 | *.mobileprovision 8 | env.ts -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /rn-cli.config.js: -------------------------------------------------------------------------------- 1 | // const extraNodeModules = require('node-libs-browser') 2 | 3 | // module.exports = { 4 | // extraNodeModules: { 5 | // ...extraNodeModules, 6 | // } 7 | // } -------------------------------------------------------------------------------- /src/lib/ethereum/network.ts: -------------------------------------------------------------------------------- 1 | export enum Networks { 2 | mainnet = 'mainnet', 3 | ropsten = 'ropsten' 4 | } 5 | 6 | export const getNetwork = (): Networks => { 7 | return (process.env.NODE_ENV === 'production') ? Networks.mainnet : Networks.ropsten 8 | } -------------------------------------------------------------------------------- /App.tsx: -------------------------------------------------------------------------------- 1 | import './global' 2 | import React from 'react'; 3 | import WalletProvider from './src/components/EthereumProvider' 4 | import Wallet from './src/components/Wallet'; 5 | 6 | export default class App extends React.Component { 7 | render() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | } -------------------------------------------------------------------------------- /global.js: -------------------------------------------------------------------------------- 1 | global.Buffer = require('buffer').Buffer; 2 | global.process = require('process'); 3 | 4 | if (typeof btoa === 'undefined') { 5 | global.btoa = function (str) { 6 | return new Buffer(str, 'binary').toString('base64'); 7 | }; 8 | } 9 | 10 | if (typeof atob === 'undefined') { 11 | global.atob = function (b64Encoded) { 12 | return new Buffer(b64Encoded, 'base64').toString('binary'); 13 | }; 14 | } 15 | 16 | global.self = global -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "allowSyntheticDefaultImports": true, 5 | "noFallthroughCasesInSwitch": true, 6 | "experimentalDecorators": true, 7 | "esModuleInterop": true, 8 | "isolatedModules": true, 9 | "jsx": "react-native", 10 | "lib": [ 11 | "es6" 12 | ], 13 | "moduleResolution": "node", 14 | "noEmit": true, 15 | "strict": true, 16 | "target": "esnext" 17 | }, 18 | "exclude": [ 19 | "node_modules" 20 | ] 21 | } -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "Swysh", 4 | "slug": "swysh-wallet", 5 | "privacy": "public", 6 | "sdkVersion": "32.0.0", 7 | "platforms": [ 8 | "ios", 9 | "android" 10 | ], 11 | "version": "1.0.0", 12 | "orientation": "portrait", 13 | "icon": "./assets/icon.png", 14 | "splash": { 15 | "image": "./assets/splash.png", 16 | "resizeMode": "contain", 17 | "backgroundColor": "#ffffff" 18 | }, 19 | "updates": { 20 | "fallbackToCacheTimeout": 0 21 | }, 22 | "assetBundlePatterns": [ 23 | "**/*" 24 | ], 25 | "ios": { 26 | "supportsTablet": true 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /shim.js: -------------------------------------------------------------------------------- 1 | if (typeof __dirname === 'undefined') global.__dirname = '/' 2 | if (typeof __filename === 'undefined') global.__filename = '' 3 | if (typeof process === 'undefined') { 4 | global.process = require('process') 5 | } else { 6 | const bProcess = require('process') 7 | for (var p in bProcess) { 8 | if (!(p in process)) { 9 | process[p] = bProcess[p] 10 | } 11 | } 12 | } 13 | 14 | process.browser = false 15 | if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer 16 | 17 | // global.location = global.location || { port: 80 } 18 | const isDev = typeof __DEV__ === 'boolean' && __DEV__ 19 | process.env['NODE_ENV'] = isDev ? 'development' : 'production' 20 | if (typeof localStorage !== 'undefined') { 21 | localStorage.debug = isDev ? '*' : '' 22 | } 23 | 24 | // If using the crypto shim, uncomment the following line to ensure 25 | // crypto is loaded first, so it can populate global.crypto 26 | // require('crypto') 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Expo ETH and ERC20 Wallet 2 | 3 | This project is bootstrapped with [Expo](https://expo.io) 4 | 5 | Use this project as a starting point or reference for building dapps and wallets with Expo. 6 | 7 | ## Installation 8 | 9 | `yarn install` 10 | 11 | ## Using 12 | 13 | - `yarn start` 14 | - `yarn ios` or `yarn android` 15 | 16 | ## Troubleshooting 17 | 18 | If iOS simulator doesn't open try running `open -a Simulator` first 19 | 20 | ## License (MIT) 21 | 22 | ``` 23 | WWWWWW||WWWWWW 24 | W W W||W W W 25 | || 26 | ( OO )__________ 27 | / | \ 28 | /o o| MIT \ 29 | \___/||_||__||_|| * 30 | || || || || 31 | _||_|| _||_|| 32 | (__|__|(__|__| 33 | ``` 34 | Copyright © 2019-present [Jason Werner](https://trxrg.com), jason@trxrg.com 35 | 36 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 39 | 40 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/components/EthereumProvider.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ethers } from "ethers"; 3 | import { 4 | createWallet, 5 | loadWallet, 6 | sendAsset, 7 | WalletStorageType 8 | } from "../lib/ethereum/wallet"; 9 | import { loadAssets, AssetType, Asset } from "../lib/ethereum/assets"; 10 | 11 | const ASSETS = [AssetType.eth, AssetType.dai]; 12 | 13 | export interface Ethereum { 14 | wallet: ethers.Wallet; 15 | assets: Asset[]; 16 | sendAsset: (to: string, amount: number, type: AssetType) => Promise; 17 | createWallet: () => void; 18 | loading: boolean; 19 | } 20 | 21 | export const EthereumContext = React.createContext({} as Ethereum); 22 | 23 | interface EthereumProviderProps { 24 | children: JSX.Element; 25 | } 26 | 27 | class EthereumProvider extends React.Component { 28 | state = { loading: true } as Ethereum; 29 | 30 | public componentDidMount = async () => { 31 | try { 32 | const wallet = await loadWallet(WalletStorageType.privateKey); 33 | const assets = await loadAssets(ASSETS, wallet); 34 | this.setState({ wallet, assets, loading: false }); 35 | } catch (e) { 36 | console.log("ERROR", e); 37 | this.setState({ loading: false }); 38 | } 39 | }; 40 | 41 | public sendAsset = async (to: string, amount: number, type: AssetType): Promise => { 42 | const transaction = await sendAsset({ 43 | wallet: this.state.wallet, 44 | to, 45 | amount, 46 | type 47 | }); 48 | console.log("transaction", transaction); 49 | return transaction 50 | }; 51 | 52 | public createWallet = async () => { 53 | this.setState({ loading: true }); 54 | const wallet = await createWallet(); 55 | const assets = await loadAssets(ASSETS, wallet); 56 | this.setState({ wallet, assets, loading: false }); 57 | }; 58 | 59 | public render() { 60 | const { children } = this.props; 61 | const value = { 62 | ...this.state, 63 | createWallet: this.createWallet, 64 | sendAsset: this.sendAsset 65 | }; 66 | return ( 67 | 68 | {children} 69 | 70 | ); 71 | } 72 | } 73 | 74 | export default EthereumProvider; 75 | -------------------------------------------------------------------------------- /src/lib/ethereum/wallet.ts: -------------------------------------------------------------------------------- 1 | import { SecureStore } from 'expo' 2 | import { ethers } from 'ethers' 3 | import { AssetType, sendEther, sendToken } from './assets' 4 | import { getNetwork } from './network' 5 | 6 | const PRIVATE_KEY_STORAGE_KEY = 'Ethereum.privatekey' 7 | 8 | export enum WalletStorageType { 9 | privateKey = 'PRIVATE_KEY', 10 | mnemonics = 'MNEMONICS' 11 | } 12 | 13 | const generateMnemonics = () => { 14 | return ethers.utils.HDNode.entropyToMnemonic(ethers.utils.randomBytes(16)).split(' ') 15 | } 16 | 17 | const loadWalletFromMnemonics = async (mnemonics: string[]) => { 18 | if (!(mnemonics instanceof Array)) throw new Error('invalid mnemonic'); 19 | 20 | const provider = ethers.getDefaultProvider(getNetwork()) 21 | provider.getBalance = provider.getBalance.bind(provider) 22 | const wallet = ethers.Wallet.fromMnemonic(mnemonics.join(' ')).connect(provider) 23 | return wallet 24 | } 25 | 26 | const loadWalletFromPrivateKey = async (privateKey: string): Promise => { 27 | const provider = ethers.getDefaultProvider(getNetwork()) 28 | provider.getBalance = provider.getBalance.bind(provider) 29 | const wallet = new ethers.Wallet(privateKey, provider) 30 | return wallet 31 | } 32 | 33 | export const createWallet = async (): Promise => { 34 | const mnemonics = generateMnemonics() 35 | const wallet = await loadWalletFromMnemonics(mnemonics) 36 | await SecureStore.setItemAsync(PRIVATE_KEY_STORAGE_KEY, JSON.stringify(wallet.privateKey)) 37 | return wallet 38 | } 39 | 40 | export const loadWallet = async (type: WalletStorageType, mnemonics?: string[]): Promise => { 41 | switch(type) { 42 | case WalletStorageType.privateKey: 43 | const privateKey = await SecureStore.getItemAsync(PRIVATE_KEY_STORAGE_KEY) 44 | if (!privateKey) throw new Error(`No private key in storage`) 45 | return loadWalletFromPrivateKey(JSON.parse(privateKey)) 46 | case WalletStorageType.mnemonics: 47 | if (!mnemonics) throw new Error(`No mnemonics provided`) 48 | return loadWalletFromMnemonics(mnemonics) 49 | } 50 | } 51 | 52 | export const sendAsset = async (args: { wallet: ethers.Wallet, to: string, amount: number, type: AssetType }): Promise => { 53 | const { type } = args 54 | return type === AssetType.eth ? sendEther(args) : sendToken(args) 55 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "expo-eth-wallet", 3 | "displayName": "ETH and ERC20 wallet built with Expo", 4 | "version": "0.0.1", 5 | "private": true, 6 | "main": "node_modules/expo/AppEntry.js", 7 | "scripts": { 8 | "start": "expo start", 9 | "android": "expo start --android", 10 | "ios": "expo start --ios", 11 | "eject": "expo eject", 12 | "postinstall": "node_modules/.bin/rn-nodeify --install stream,http,https,os,vm,crypto --yarn --hack" 13 | }, 14 | "dependencies": { 15 | "@tradle/react-native-http": "^2.0.0", 16 | "crypto-browserify": "^3.12.0", 17 | "ethers": "^4.0.27", 18 | "expo": "^32.0.0", 19 | "https-browserify": "~0.0.0", 20 | "node-libs-browser": "^2.2.0", 21 | "react": "16.5.0", 22 | "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz", 23 | "react-native-crypto": "^2.1.2", 24 | "react-native-os": "^1.0.1", 25 | "react-native-randombytes": "^3.5.3", 26 | "readable-stream": "1.0.33", 27 | "stream-browserify": "^1.0.0", 28 | "stream-http": "^3.0.0", 29 | "web3": "^1.0.0-beta.55" 30 | }, 31 | "devDependencies": { 32 | "@types/expo": "^32.0.0", 33 | "@types/react-native": "^0.57.0", 34 | "babel-preset-expo": "^5.0.0", 35 | "rn-nodeify": "^10.0.1", 36 | "typescript": "^3.3.0" 37 | }, 38 | "react-native": { 39 | "crypto": "react-native-crypto", 40 | "http": "@tradle/react-native-http", 41 | "https": "https-browserify", 42 | "os": "react-native-os", 43 | "_stream_transform": "readable-stream/transform", 44 | "_stream_readable": "readable-stream/readable", 45 | "_stream_writable": "readable-stream/writable", 46 | "_stream_duplex": "readable-stream/duplex", 47 | "_stream_passthrough": "readable-stream/passthrough", 48 | "stream": "stream-browserify", 49 | "vm": "vm-browserify" 50 | }, 51 | "browser": { 52 | "crypto": "react-native-crypto", 53 | "http": "@tradle/react-native-http", 54 | "https": "https-browserify", 55 | "os": "react-native-os", 56 | "_stream_transform": "readable-stream/transform", 57 | "_stream_readable": "readable-stream/readable", 58 | "_stream_writable": "readable-stream/writable", 59 | "_stream_duplex": "readable-stream/duplex", 60 | "_stream_passthrough": "readable-stream/passthrough", 61 | "stream": "stream-browserify", 62 | "vm": "vm-browserify" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/components/Wallet.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { StyleSheet, Text, View, TouchableOpacity, ActivityIndicator } from "react-native"; 3 | import { ethers } from "ethers"; 4 | import { EthereumContext } from "./EthereumProvider"; 5 | import { Asset, AssetType } from "../lib/ethereum/assets"; 6 | 7 | class Wallet extends React.Component<{ 8 | assets: Asset[]; 9 | wallet: ethers.Wallet; 10 | createWallet: () => void 11 | sendAsset: (to: string, amount: number, type: AssetType) => Promise 12 | }> { 13 | state = { network: '' }; 14 | 15 | public componentDidMount = async () => { 16 | if (this.props.wallet) { 17 | const network = await this.props.wallet.provider.getNetwork() 18 | this.setState({ network: network.name }) 19 | } 20 | } 21 | 22 | public render() { 23 | const { network } = this.state 24 | const { assets, wallet, createWallet, sendAsset } = this.props; 25 | return !wallet ? ( 26 | 27 | 28 | Create Wallet 29 | 30 | 31 | ) : ( 32 | 33 | {network} 34 | {assets.map(asset => ( 35 | 36 | {asset.type} 37 | {wallet.address} 38 | Balance: {asset.balance} 39 | sendAsset('0x24440C989754C4Ab1636c24d19e19aAb9D068493', 0.1, asset.type)}> 40 | Send 0.1 41 | 42 | 43 | ))} 44 | 45 | ); 46 | } 47 | } 48 | 49 | const WalletWithData = () => ( 50 | 51 | {({ assets, wallet, createWallet, sendAsset, loading }) => 52 | loading ? ( 53 | 54 | 55 | 56 | ) : ( 57 | 58 | ) 59 | } 60 | 61 | ); 62 | 63 | const styles = StyleSheet.create({ 64 | container: { 65 | flex: 1, 66 | backgroundColor: "#fff", 67 | alignItems: "flex-end", 68 | justifyContent: "center" 69 | }, 70 | centerContainer: { 71 | flex: 1, 72 | backgroundColor: "#fff", 73 | alignItems: "center", 74 | justifyContent: "center" 75 | }, 76 | row: { 77 | margin: 5 78 | } 79 | }); 80 | 81 | export default WalletWithData; 82 | -------------------------------------------------------------------------------- /src/lib/ethereum/assets.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers' 2 | import { Networks } from './network' 3 | import erc20ABI, { ERC20Contract } from './contracts/erc20' 4 | 5 | export enum AssetType { 6 | eth = 'ETH', 7 | dai = 'DAI', 8 | } 9 | 10 | export interface Asset { 11 | type: AssetType 12 | balance: number, 13 | } 14 | 15 | const TOKENS = { 16 | [Networks.mainnet]: { 17 | [AssetType.dai]: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359' 18 | }, 19 | [Networks.ropsten]: { 20 | [AssetType.dai]: '0xad6d458402f60fd3bd25163575031acdce07538d' 21 | } 22 | } 23 | 24 | export const sendEther = async (args: { wallet: ethers.Wallet, to: string, amount: number }): Promise => { 25 | const { wallet, to, amount } = args 26 | const network = await wallet.provider.getNetwork() 27 | const transaction = await wallet.sendTransaction({ 28 | to, 29 | value: ethers.utils.parseEther(amount.toString()), 30 | chainId: network.chainId 31 | }); 32 | return transaction 33 | } 34 | 35 | export const sendToken = async (args: { wallet: ethers.Wallet, to: string, amount: number, type: AssetType }): Promise => { 36 | const { wallet, to, amount, type } = args 37 | 38 | if (type === AssetType.eth) throw new Error('Use sendEther function to send ETH') 39 | 40 | const network = await wallet.provider.getNetwork() 41 | const tokenAddress = TOKENS[network.name as Networks][type] 42 | const contract = new ethers.Contract(tokenAddress, erc20ABI, wallet) as ERC20Contract 43 | const decimals = await contract.decimals() 44 | const transaction = await contract.transfer(to, ethers.utils.parseUnits(amount.toString(), decimals)) 45 | return transaction 46 | } 47 | 48 | export const getEtherBalance = async (wallet: ethers.Wallet): Promise => { 49 | const balance = await wallet.provider.getBalance(wallet.address) 50 | return Number(ethers.utils.formatEther(balance)) 51 | } 52 | 53 | export const getTokenBalance = async (tokenAddress: string, wallet: ethers.Wallet): Promise => { 54 | const contract = new ethers.Contract(tokenAddress, erc20ABI, wallet) as ERC20Contract 55 | const balance: ethers.utils.BigNumber = await contract.balanceOf(wallet.address); 56 | const decimals: number = await contract.decimals() 57 | const tokenBalance = ethers.utils.formatUnits(balance, decimals) 58 | return Number(tokenBalance) 59 | } 60 | 61 | export const loadAssets = async (assets: AssetType[], wallet: ethers.Wallet): Promise => { 62 | const network = await wallet.provider.getNetwork() 63 | const tokensAddresses = TOKENS[network.name as Networks] 64 | return await Promise.all(assets.map(async (asset: AssetType) => { 65 | if (asset === AssetType.eth) { 66 | return { 67 | type: asset, 68 | balance: await getEtherBalance(wallet) 69 | } 70 | } else { 71 | return { 72 | type: asset, 73 | balance: await getTokenBalance(tokensAddresses[asset], wallet) 74 | } 75 | } 76 | })) 77 | } -------------------------------------------------------------------------------- /src/lib/ethereum/contracts/erc20.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers' 2 | 3 | export interface ERC20Contract extends ethers.Contract { 4 | name: () => Promise 5 | approve: (spender: string, value: ethers.utils.BigNumber) => Promise 6 | totalSupply: () => Promise 7 | transferFrom: (from: string, to: string, value: ethers.utils.BigNumber) => Promise 8 | decimals: () => Promise 9 | balanceOf: (owner: string) => Promise 10 | symbol: () => Promise 11 | transfer: (to: string, value: ethers.utils.BigNumber) => Promise 12 | allowance: (owner: string, spender: string) => Promise 13 | } 14 | 15 | // ERC20 ABI // 16 | export default [ 17 | //* name(): string 18 | { 19 | constant: true, 20 | inputs: [], 21 | name: "name", 22 | outputs: [ 23 | { 24 | name: "", 25 | type: "string" 26 | } 27 | ], 28 | payable: false, 29 | stateMutability: "view", 30 | type: "function" 31 | }, 32 | //* approve(spender: string, value: BigNumber): boolean 33 | { 34 | constant: false, 35 | inputs: [ 36 | { 37 | name: "_spender", 38 | type: "address" 39 | }, 40 | { 41 | name: "_value", 42 | type: "uint256" 43 | } 44 | ], 45 | name: "approve", 46 | outputs: [ 47 | { 48 | name: "", 49 | type: "bool" 50 | } 51 | ], 52 | payable: false, 53 | stateMutability: "nonpayable", 54 | type: "function" 55 | }, 56 | //* totalSupply(): BigNumber 57 | { 58 | constant: true, 59 | inputs: [], 60 | name: "totalSupply", 61 | outputs: [ 62 | { 63 | name: "", 64 | type: "uint256" 65 | } 66 | ], 67 | payable: false, 68 | stateMutability: "view", 69 | type: "function" 70 | }, 71 | //* transferFrom(from: string, to: string, value: number): boolean 72 | { 73 | constant: false, 74 | inputs: [ 75 | { 76 | name: "_from", 77 | type: "address" 78 | }, 79 | { 80 | name: "_to", 81 | type: "address" 82 | }, 83 | { 84 | name: "_value", 85 | type: "uint256" 86 | } 87 | ], 88 | name: "transferFrom", 89 | outputs: [ 90 | { 91 | name: "", 92 | type: "bool" 93 | } 94 | ], 95 | payable: false, 96 | stateMutability: "nonpayable", 97 | type: "function" 98 | }, 99 | //* decimals(): number 100 | { 101 | constant: true, 102 | inputs: [], 103 | name: "decimals", 104 | outputs: [ 105 | { 106 | name: "", 107 | type: "uint8" 108 | } 109 | ], 110 | payable: false, 111 | stateMutability: "view", 112 | type: "function" 113 | }, 114 | //* balanceOf(owner: string): BigNumber 115 | { 116 | constant: true, 117 | inputs: [ 118 | { 119 | name: "_owner", 120 | type: "address" 121 | } 122 | ], 123 | name: "balanceOf", 124 | outputs: [ 125 | { 126 | name: "balance", 127 | type: "uint256" 128 | } 129 | ], 130 | payable: false, 131 | stateMutability: "view", 132 | type: "function" 133 | }, 134 | //* symbol(): string 135 | { 136 | constant: true, 137 | inputs: [], 138 | name: "symbol", 139 | outputs: [ 140 | { 141 | name: "", 142 | type: "string" 143 | } 144 | ], 145 | payable: false, 146 | stateMutability: "view", 147 | type: "function" 148 | }, 149 | //* transfer(to: string, value: number): boolean 150 | { 151 | constant: false, 152 | inputs: [ 153 | { 154 | name: "_to", 155 | type: "address" 156 | }, 157 | { 158 | name: "_value", 159 | type: "uint256" 160 | } 161 | ], 162 | name: "transfer", 163 | outputs: [ 164 | { 165 | name: "", 166 | type: "bool" 167 | } 168 | ], 169 | payable: false, 170 | stateMutability: "nonpayable", 171 | type: "function" 172 | }, 173 | //* allowance(owner: string, spender: string): BigNumber 174 | { 175 | constant: true, 176 | inputs: [ 177 | { 178 | name: "_owner", 179 | type: "address" 180 | }, 181 | { 182 | name: "_spender", 183 | type: "address" 184 | } 185 | ], 186 | name: "allowance", 187 | outputs: [ 188 | { 189 | name: "", 190 | type: "uint256" 191 | } 192 | ], 193 | payable: false, 194 | stateMutability: "view", 195 | type: "function" 196 | }, 197 | { 198 | payable: true, 199 | stateMutability: "payable", 200 | type: "fallback" 201 | }, 202 | { 203 | anonymous: false, 204 | inputs: [ 205 | { 206 | indexed: true, 207 | name: "owner", 208 | type: "address" 209 | }, 210 | { 211 | indexed: true, 212 | name: "spender", 213 | type: "address" 214 | }, 215 | { 216 | indexed: false, 217 | name: "value", 218 | type: "uint256" 219 | } 220 | ], 221 | name: "Approval", 222 | type: "event" 223 | }, 224 | { 225 | anonymous: false, 226 | inputs: [ 227 | { 228 | indexed: true, 229 | name: "from", 230 | type: "address" 231 | }, 232 | { 233 | indexed: true, 234 | name: "to", 235 | type: "address" 236 | }, 237 | { 238 | indexed: false, 239 | name: "value", 240 | type: "uint256" 241 | } 242 | ], 243 | name: "Transfer", 244 | type: "event" 245 | } 246 | ]; 247 | --------------------------------------------------------------------------------