[ethereum] web3.js와 같은 ethers 알아보기
ethers는 web3.js처럼 이더리움 네트워크를 조회하고 조작할 수 있는 인터페이스를 제공하는 라이브러리입니다. 그렇다면 web3.js대신 ethers.js를 사용해야하는 이유는 무엇일까?
ethers는 provider와 signer를 주입하는 형태로 유연한 코드 작성이 가능하다고 생각합니다.
· 설치
$ npm install --save ethers
ethers는 크게 4개의 객체를 제공합니다.
▶ CommonJS
const { providers, Wallet, utils, Contract } = require('ethers');
▶ ESM
import { providers, Wallet, utils, Contract } from "ethers";
▶ CDN
<script type="module">
import { providers, Wallet, utils, Contract } from "https://cdn.ethers.io/lib/ethers-5.2.esm.min.js";
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ethers/5.6.9/ethers.umd.min.js" integrity="sha512-Veaz5IU2iRpa0BBrJlJeRgfJ7OAHWtVJZTXvgdH7s3ffsLUChllMCqC0Bb+eeRxGlrZ06iYIE/R3KsciCrgv3A==" crossorigin="anonymous" referrerpolicy="no-referrer">
</script>
<script>
const { providers, Wallet, utils, Contract } = ethers.ethers;
</script>
● providers
providers는 이더리움 노드와 연결합니다. 블록, 트랜잭션 조회등을 수행할 수 있습니다.
· 노드연결
const provider = new providers.JsonRpcProvider(url);
const provider = new providers.JsonRpcProvider('http://localhost:8545');
만약, metamask의 provider를 이용하고 싶다면 다음과 같이 이용할 수 있습니다.
const provider = new ethers.providers.Web3Provider(window.ethereum)
· 최근 블록번호 조회
const block = await provider.getBlockNumber()
· 블록조회
const block0 = await provider.getBlock(0)
{
hash: '0xe4b7283f03a18236615e883d91595dc6cf12119ed14d0179c7e29f5f80f2c94d',
parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
number: 0,
timestamp: 1650158272,
nonce: '0x0000000000000000',
difficulty: 0,
gasLimit: BigNumber { _hex: '0x6691b7', _isBigNumber: true },
gasUsed: BigNumber { _hex: '0x00', _isBigNumber: true },
miner: '0x0000000000000000000000000000000000000000',
extraData: '0x',
transactions: [],
_difficulty: BigNumber { _hex: '0x00', _isBigNumber: true }
}
const txs = await provider.getBlockWithTransactions(0)
{
hash: '0xe4b7283f03a18236615e883d91595dc6cf12119ed14d0179c7e29f5f80f2c94d',
parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
number: 0,
timestamp: 1650158272,
nonce: '0x0000000000000000',
difficulty: 0,
gasLimit: BigNumber { _hex: '0x6691b7', _isBigNumber: true },
gasUsed: BigNumber { _hex: '0x00', _isBigNumber: true },
miner: '0x0000000000000000000000000000000000000000',
extraData: '0x',
transactions: [],
_difficulty: BigNumber { _hex: '0x00', _isBigNumber: true }
}
getBlock과 getBlockWithTransactions의 차이는 transactions에 있습니다. getBlock은 트랜잭션 해시 목록을 가지고 있으며 getBlockWithTransactions는 트랜잭션 객체목록을 가지고 있습니다.
· 트랜잭션 조회
const tx = await provider.getTransaction("0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0");
{
accessList: null,
blockHash: '0x8a179bc6cb299f936c4fd614995e62d597ec6108b579c23034fb220967ceaa94',
blockNumber: 12598244,
chainId: 1,
confirmations: 1869134,
creates: '0x733aF852514e910E2f8af40d61E00530377889E9',
data: '0x608060405234801561001057600080fd5b5060405161062438038061062483398101604081905261002f916100cd565b60405163c47f002760e01b815260206004820152600d60248201526c0daead8e8d2c6c2d8d85ccae8d609b1b60448201526001600160a01b0382169063c47f002790606401602060405180830381600087803b15801561008e57600080fd5b505af11580156100a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100c691906100fb565b5050610113565b6000602082840312156100de578081fd5b81516001600160a01b03811681146100f4578182fd5b9392505050565b60006020828403121561010c578081fd5b5051919050565b610502806101226000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80634c0770b914610030575b600080fd5b61004361003e366004610309565b61005b565b60405161005293929190610389565b60405180910390f35b600060608085841461006c57600080fd5b8567ffffffffffffffff81111561009357634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156100bc578160200160208202803683370190505b5091508567ffffffffffffffff8111156100e657634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561011957816020015b60608152602001906001900390816101045790505b50905060005b86811015610235576101cd8a8a8a8a8581811061014c57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061016191906102db565b89898681811061018157634e487b7160e01b600052603260045260246000fd5b90506020028101906101939190610460565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061024592505050565b8483815181106101ed57634e487b7160e01b600052603260045260246000fd5b6020026020010184848151811061021457634e487b7160e01b600052603260045260246000fd5b6020908102919091010191909152528061022d816104a5565b91505061011f565b5043925096509650969350505050565b6000606060405190506000815260208101604052600080845160208601878afa9150843d101561028857603f3d01601f191681016040523d81523d6000602083013e5b94509492505050565b60008083601f8401126102a2578182fd5b50813567ffffffffffffffff8111156102b9578182fd5b6020830191508360208260051b85010111156102d457600080fd5b9250929050565b6000602082840312156102ec578081fd5b81356001600160a01b0381168114610302578182fd5b9392505050565b60008060008060008060808789031215610321578182fd5b8635955060208701359450604087013567ffffffffffffffff80821115610346578384fd5b6103528a838b01610291565b9096509450606089013591508082111561036a578384fd5b5061037789828a01610291565b979a9699509497509295939492505050565b60006060820185835260206060818501528186518084526080860191508288019350845b818110156103c9578451835293830193918301916001016103ad565b5050848103604086015285518082528282019350600581901b82018301838801865b8381101561045057601f1980868503018852825180518086528a5b81811015610421578281018a01518782018b01528901610406565b81811115610431578b8a83890101525b5098880198601f019091169390930186019250908501906001016103eb565b50909a9950505050505050505050565b6000808335601e19843603018112610476578283fd5b83018035915067ffffffffffffffff821115610490578283fd5b6020019150368190038213156102d457600080fd5b60006000198214156104c557634e487b7160e01b81526011600452602481fd5b506001019056fea264697066735822122083b5dc25b3c9256aa4244eddaf9e4b5fccd09a45ec4e0174f2c900de7144602d64736f6c63430008040033000000000000000000000000084b1c3c81545d370f3634392de611caabff8148',
from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
gasLimit: { BigNumber: "443560" },
gasPrice: { BigNumber: "10100000000" },
hash: '0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0',
nonce: 745,
r: '0xaf2b969de6dfb234fb8843f47a029636abb1ef52f26bb8bb615bbabcf23808e9',
s: '0x3dd61cd8df015e0af5689a249dd3224ee71f2b04917b7b4c14f7e68bb3a4ec17',
to: null,
transactionIndex: 315,
type: 0,
v: 38,
value: { BigNumber: "0" },
wait: [Function]
}
const tx = await provider.getTransactionReceipt("0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0");
{
blockHash: '0x8a179bc6cb299f936c4fd614995e62d597ec6108b579c23034fb220967ceaa94',
blockNumber: 12598244,
byzantium: true,
confirmations: 1869134,
contractAddress: '0x733aF852514e910E2f8af40d61E00530377889E9',
cumulativeGasUsed: { BigNumber: "12102324" },
effectiveGasPrice: { BigNumber: "10100000000" },
from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
gasUsed: { BigNumber: "443560" },
logs: [
{
address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
blockHash: '0x8a179bc6cb299f936c4fd614995e62d597ec6108b579c23034fb220967ceaa94',
blockNumber: 12598244,
data: '0x000000000000000000000000084b1c3c81545d370f3634392de611caabff8148',
logIndex: 160,
topics: [
'0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82',
'0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2',
'0x4774f6d3b3d08b5ec00115f0e2fddb92604b39e52b0dc908c6f8fcb7aa5d2a9a'
],
transactionHash: '0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0',
transactionIndex: 315
},
{
address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
blockHash: '0x8a179bc6cb299f936c4fd614995e62d597ec6108b579c23034fb220967ceaa94',
blockNumber: 12598244,
data: '0x000000000000000000000000a2c122be93b0074270ebee7f6b7292c7deb45047',
logIndex: 161,
topics: [
'0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0',
'0x790fdce97f7b2b1c4c5a709fb6a49bf878feffcaa85ed0245f6dff09abcefda7'
],
transactionHash: '0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0',
transactionIndex: 315
}
],
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000004000000000000010000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000040000000000000000100004000000000000008000040000000000000000000000000000000000005000000000041000000000000000000000000000000000000000000000000100000000000000001000000000000000000000',
status: 1,
to: null,
transactionHash: '0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0',
transactionIndex: 315,
type: 0
}
· 이더조회
const balance = await provider.getBalance('0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17')
BigNumber { _hex: '0x056bc75e2d63100000', _isBigNumber: true }
단위변경은 utils를 이용하면 됩니다.
· 수수료 조회
트랜잭션을 만들기 위해 필요한 수수료 조회 메서드입니다. 이는 EIP1559 방식을 기준으로 조회합니다.
const fee = await provider.getFeeData();
{
maxFeePerGas: null,
maxPriorityFeePerGas: null,
gasPrice: BigNumber { _hex: '0x04a817c800', _isBigNumber: true }
}
maxFeePerGas와 maxPriorityFeePerGas 모두 gasPrice와 같은 데이터 타입을 가집니다.
· 수수료 추청
트랜잭션이 정상적으로 실행되었을 때 사용되는 가스량 추청을 할 수 있습니다.
await provider.estimateGas({
to: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // Wrapped ETH address
data: "0xd0e30db0", // `function deposit() payable`
value: parseEther("1.0") // 1 ether
});
{ BigNumber: "27938" }
· nonce 조회
nonce란 발생된 트랜잭션 수 입니다.
const address = '0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17';
const nonce = await provider.getTransactionCount(address, "latest")
0
· 트랜잭션 발생
const signedTx = "0xf8690401825208945555763613a12d8f3e73be831dff8598089d3dca882b992b75cbeb600080820a96a0e3767d1e99c6090a5d00532fe11e2acf3be9228f1f8df7ce9d3c5c6ca3dac151a0594869ee73fbf7394c82e080b1bc734536b67832d2abab5b7bedc79f297bb338";
await provider.sendTransaction(signedTx);
{
chainId: 1337,
confirmations: 0,
data: '0x',
from: '0x77C44C0D1D37050e9250415Ee96401B5ac270856',
gasLimit: { BigNumber: "21000" },
gasPrice: { BigNumber: "1" },
hash: '0x1c392c05e5f293ce4e1367101233513ce09575c67d7f3ee519d59c2d22b9dde9',
nonce: 4,
r: '0xe3767d1e99c6090a5d00532fe11e2acf3be9228f1f8df7ce9d3c5c6ca3dac151',
s: '0x594869ee73fbf7394c82e080b1bc734536b67832d2abab5b7bedc79f297bb338',
to: '0x5555763613a12D8F3e73be831DFf8598089d3dCa',
type: null,
v: 2710,
value: { BigNumber: "3141590000000000000" },
wait: [Function]
}
서명된 트랜잭은 다음과 같이 만들 수 있습니다.
const signer = Wallet.createRandom()
const signed = await signer.signTransaction({
to: '0x6BAE09696c44D0fcF157Cf72b1930632AF435A97',
from: signer.address,
value: utils.parseEther('0.1'),
})
await provider.sendTransaction(signedTx);
또한 sendTransaction은 서명된 문자열이 아닌 오브젝트를 받을 수 있습니다. 이때 from은 생성된 지갑주소가 들어갑니다. wallet을 생성하고 니모닉, 키스토어 파일, 개인키를 이용하여 복구하는 방법은 아래에서 다룹니다.
const signer = Wallet.createRandom()
const txHash = await signer.sendTransaction({
to: '0xAd46355359aE32263EaFE152a408D9D620844eda',
value: utils.parseUnits('0.1', 'ether').toHexString()
})
· 이벤트 수신
provider.on('block', (block) => {
console.log(block)
})
1
2
3
해당 네트워크에 블록이 생성되면 생성된 블록번호를 전달받습니다.
provider.on("pending", (tx) => {
console.log(tx)
});
{
hash: '0x5a224e5f2ab73bfbe382dda2260adb8c5e2957606991b8b9b2ab7c33324c8323',
type: 0,
accessList: null,
blockHash: '0xb13106233b4173006fda0e39bd2af24264d49f1b88f2f828b0b4f1fd3fee77b6',
blockNumber: 9,
transactionIndex: 0,
confirmations: 1,
from: '0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17',
gasPrice: BigNumber { _hex: '0x04a817c800', _isBigNumber: true },
gasLimit: BigNumber { _hex: '0x011a59', _isBigNumber: true },
to: null,
value: BigNumber { _hex: '0x00', _isBigNumber: true },
nonce: 8,
data: '0x60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122024e006b709493803f07277c09b5c327910ed1595e233a5d24959eacff659640364736f6c634300080d0033',
r: '0xa93dc61c988f92aba88db265bdcd03e8412066c2d2b409c97b34ab8da882aa1a',
s: '0x71babaf613b91c91a6979661dae2f28dfb1d5e7f9e9c2abbac7d84f5e286a516',
v: 38,
creates: '0x85E8E89867bc699278Da7276d32E4fd856B3Afc8',
chainId: 1,
wait: [Function (anonymous)]
}
팬딩중인 트랜잭션을 수신합니다.
● Wallet
Wallet은 개인키/공개키를 관리합니다.
· 키(주소) 생성
const signer = Wallet.createRandom()
console.log(signer)
console.log(signer._signingKey())
console.log(signer._mnemonic())
Wallet {
_isSigner: true,
_signingKey: [Function (anonymous)],
address: '0xf3a1F20176cd7F877737012ca8FCd3e32B5bbc81',
_mnemonic: [Function (anonymous)],
provider: null
}
SigningKey {
curve: 'secp256k1',
privateKey: '0xc9ea026885ea45fd27d06049614bc1e6474fd5208dcd008a25e4f5c8297a11fd',
publicKey: '0x0462c4b51b0a8623510168d1ac42d8731bbd38b6aa3c037b96782b987e76d695913efa32b8552d42c51fd7dc2c6ff06c8e17d75beeda5e55fa7da955850fe50ef4',
compressedPublicKey: '0x0262c4b51b0a8623510168d1ac42d8731bbd38b6aa3c037b96782b987e76d69591',
_isSigningKey: true
}
{
phrase: 'clown unveil parrot rebuild trial convince box glass gun trumpet garbage electric',
path: "m/44'/60'/0'/0/0",
locale: 'en'
}
create 메서드를 이용하면 키스토어를 생성할 수 있습니다.
const password = '123456'
const signer = Wallet.createRandom()
const keystore = await signer.encrypt(password);
console.log(keystore)
{"address":"84db1f6c4b16cda79f4dc34404445fabe55b97bf","id":"fb49150e-baa5-4325-a3c1-4f8547c118cb","version":3,"Crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"39fe92c0b9ccba464e25e63686695f05"},"ciphertext":"476c18b348830e566c815df1669e281e45777e282494deea857425864b778421","kdf":"scrypt","kdfparams":{"salt":"a4f06b8ee274dbb763e540cf93d3cded6ceaa43a928381c463767b7e2ee76f33","n":131072,"dklen":32,"p":1,"r":8},"mac":"3aed307763f9e53e5f3bd9533922546c554fbf8db20608c99a08103c18d7e924"},"x-ethers":{"client":"ethers.js","gethFilename":"UTC--2022-04-17T02-06-38.0Z--84db1f6c4b16cda79f4dc34404445fabe55b97bf","mnemonicCounter":"08d67dd51426a9488c97ed1ca75f3e82","mnemonicCiphertext":"b9c25a345f6bef62ea2fc287c1cc123c","path":"m/44'/60'/0'/0/0","locale":"en","version":"0.1"}}
· 지갑복구
지갑 복구는 크게 3가지 방법이 있습니다. 개인키 복구, 키스토어 파일 복구, 니모닉 복구
▶ 개인키 복구
const pk = '0xe6deaed561bbeb9ebc1941b10beb9ff060060d9ea637554abe475eb8f1b13ddc';
const signer = new Wallet(pk)
console.log(signer)
Wallet {
_isSigner: true,
_signingKey: [Function (anonymous)],
_mnemonic: [Function (anonymous)],
address: '0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17',
}
▶ 키스토어 파일 복구
const password = '123456'
const keystore = {"address":"84db1f6c4b16cda79f4dc34404445fabe55b97bf","id":"fb49150e-baa5-4325-a3c1-4f8547c118cb","version":3,"Crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"39fe92c0b9ccba464e25e63686695f05"},"ciphertext":"476c18b348830e566c815df1669e281e45777e282494deea857425864b778421","kdf":"scrypt","kdfparams":{"salt":"a4f06b8ee274dbb763e540cf93d3cded6ceaa43a928381c463767b7e2ee76f33","n":131072,"dklen":32,"p":1,"r":8},"mac":"3aed307763f9e53e5f3bd9533922546c554fbf8db20608c99a08103c18d7e924"},"x-ethers":{"client":"ethers.js","gethFilename":"UTC--2022-04-17T02-06-38.0Z--84db1f6c4b16cda79f4dc34404445fabe55b97bf","mnemonicCounter":"08d67dd51426a9488c97ed1ca75f3e82","mnemonicCiphertext":"b9c25a345f6bef62ea2fc287c1cc123c","path":"m/44'/60'/0'/0/0","locale":"en","version":"0.1"}}
const signer = await Wallet.fromEncryptedJson(JSON.stringify(keystore), password)
console.log(signer)
Wallet {
_isSigner: true,
_signingKey: [Function (anonymous)],
address: '0x84db1f6c4B16CdA79F4dc34404445fabE55B97bF',
_mnemonic: [Function (anonymous)],
provider: null
}
▶ 니모닉 복구
const mnemonic = "announce room limb pattern dry unit scale effort smooth jazz weasel alcohol"
const signer = Wallet.fromMnemonic(mnemonic)
console.log(signer)
Wallet {
_isSigner: true,
_signingKey: [Function (anonymous)],
address: '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1',
_mnemonic: [Function (anonymous)],
provider: null
}
· 서명하기
서명은 트랜잭션 서명과 메시지 서명이 있습니다.
▶ 트랜잭션 서명
const signer = Wallet.createRandom()
const signed = await signer.signTransaction({
to: '0x6BAE09696c44D0fcF157Cf72b1930632AF435A97',
from: signer.address,
value: utils.parseEther('0.1'),
})
console.log(signed)
0xf865808080946bae09696c44d0fcf157cf72b1930632af435a9788016345785d8a0000801ba03d0a131d414b315f5696c93627d188ca8651a31785f3b8d243c82476dd1ede56a00bc31b5e094d9ed1f3b503d96ed125009f03f3ea853d058255dc4484e232f9b5
▶ 메시지 서명
const signer = Wallet.createRandom()
const signed = await signer.signMessage("Hello World")
console.log(signed)
0xfd5a5ffed4227cd31d374b40f8ba59ed4702a74cbf6d6dca44f971525c71a6df4bb499d48f64012a7a42e13815351cc26d8fb8baef5e9a821de8db3836b84f751b
· Provider 연결
트랜잭션을 발생하기 위해선 Provider를 가지고 있어야 합니다.
const provider = new providers.JsonRpcProvider(url);
const signer = Wallet.createRandom()
const signed = await signer.signMessage("Hello World")
const wallet = signer.connect(provider)
· 이더리움 조회, nonce 조회, 트랜잭션 발생
await wallet.getBalance();
{ BigNumber: "42" }
await wallet.getTransactionCount();
0
// Sending ether
await wallet.sendTransaction(tx)
{
chainId: 1337,
confirmations: 0,
data: '0x',
from: '0x77C44C0D1D37050e9250415Ee96401B5ac270856',
gasLimit: { BigNumber: "21000" },
gasPrice: { BigNumber: "1" },
hash: '0x5037de21cbba9fbab45b779a8d4e52c610c06bb236f6e38df90a3a69f457aa12',
nonce: 5,
r: '0x62623cd493f7dc2a433c5bfa3b0d6802f498220c0ba1e3af0b9851ac8bfe8fe6',
s: '0x140682e759a02e5a6d68087ff3d531fbdacb9b6ddd637a498c83507cfe347790',
to: '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
type: null,
v: 2709,
value: { BigNumber: "1000000000000000000" },
wait: [Function]
}
● utils
utils는 이더 단위를 바꾸거나 하는 메서드를 제공합니다. 다음 내용은 ethers.utils가 export 한 목록입니다.
export {
AbiCoder,
defaultAbiCoder,
Fragment,
ConstructorFragment,
ErrorFragment,
EventFragment,
FunctionFragment,
ParamType,
FormatTypes,
checkResultErrors,
Result,
Logger,
RLP,
_fetchData,
fetchJson,
poll,
checkProperties,
deepCopy,
defineReadOnly,
getStatic,
resolveProperties,
shallowCopy,
arrayify,
concat,
stripZeros,
zeroPad,
isBytes,
isBytesLike,
defaultPath,
HDNode,
SigningKey,
Interface,
LogDescription,
TransactionDescription,
base58,
base64,
hexlify,
isHexString,
hexConcat,
hexStripZeros,
hexValue,
hexZeroPad,
hexDataLength,
hexDataSlice,
nameprep,
_toEscapedUtf8String,
toUtf8Bytes,
toUtf8CodePoints,
toUtf8String,
Utf8ErrorFuncs,
formatBytes32String,
parseBytes32String,
dnsEncode,
hashMessage,
namehash,
isValidName,
id,
_TypedDataEncoder,
getAddress,
getIcapAddress,
getContractAddress,
getCreate2Address,
isAddress,
formatEther,
parseEther,
formatUnits,
parseUnits,
commify,
computeHmac,
keccak256,
ripemd160,
sha256,
sha512,
randomBytes,
shuffled,
solidityPack,
solidityKeccak256,
soliditySha256,
splitSignature,
joinSignature,
accessListify,
parseTransaction,
serializeTransaction,
TransactionTypes,
getJsonWalletAddress,
computeAddress,
recoverAddress,
computePublicKey,
recoverPublicKey,
verifyMessage,
verifyTypedData,
getAccountPath,
mnemonicToEntropy,
entropyToMnemonic,
isValidMnemonic,
mnemonicToSeed,
////////////////////////
// Enums
SupportedAlgorithm,
UnicodeNormalizationForm,
Utf8ErrorReason,
////////////////////////
// Types
Bytes,
BytesLike,
Hexable,
AccessList,
AccessListish,
UnsignedTransaction,
CoerceFunc,
Indexed,
Mnemonic,
Deferrable,
Utf8ErrorFunc,
ConnectionInfo,
OnceBlockable,
OncePollable,
PollOptions,
FetchJsonResponse,
EncryptOptions,
ProgressCallback
}
· 단위변경
balance = await provider.getBalance("ethers.eth")
{ BigNumber: "82826475815887608" }
// wei -> ether
utils.formatEther(balance)
'0.082826475815887608'
// ether -> wei
utils.parseEther("1.0")
{ BigNumber: "1000000000000000000" }
// 특정 단위적용
utils.parseUnits('5', 'gwei')
BigNumber { _hex: '0x012a05f200', _isBigNumber: true }
0.000000005 Ether
· 주소 유효성 검사
console.log(utils.isAddress('0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17'))
console.log(utils.isAddress('0x86B6acf21e6F4aE6bAdFDBc4F5D00741823d17'))
true
false
● Contract
Contract는 트랜잭션을 발생하고 컨트랙트에서 관리하는 상태를 조회할 수 있습니다.
pragma solidity 0.8.13;
contract test {
uint public a = 10;
event onEvent1(uint indexed a);
event onEvent2(uint a);
function event1() public {
emit onEvent1(1);
}
function event2() public {
emit onEvent2(2);
}
function getA() view public returns (uint) {
return a;
}
function setA(uint _a) public {
a = _a;
}
}
CA: 0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0
· 컨트랙트 객체 생성
const ABI = [
{
"inputs": [],
"name": "event1",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "event2",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "a",
"type": "uint256"
}
],
"name": "onEvent1",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "a",
"type": "uint256"
}
],
"name": "onEvent2",
"type": "event"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_a",
"type": "uint256"
}
],
"name": "setA",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "a",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getA",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
];
const signer = new Wallet(
'0xe6deaed561bbeb9ebc1941b10beb9ff060060d9ea637554abe475eb8f1b13ddc',
provider
)
const contract = new Contract(
'0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0',
ABI,
signer
)
const rst0 = await contract.getA();
const rst1 = await contract.a();
console.log(rst0)
console.log(rst1)
BigNumber { _hex: '0x0a', _isBigNumber: true }
BigNumber { _hex: '0x0a', _isBigNumber: true }
ethers는 ABI를 다음과 같이 정의할 수 있습니다.
const ABI = [
'event onEvent1(uint indexed a)',
'event onEvent2(uint a)',
'function getA() view public returns (uint)',
'function a() view public returns (uint)',
'function setA(uint _a) public'
];
const signer = new Wallet(
'0xe6deaed561bbeb9ebc1941b10beb9ff060060d9ea637554abe475eb8f1b13ddc',
provider
)
const contract = new Contract(
'0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0',
ABI,
signer
)
const rst0 = await contract.getA();
const rst1 = await contract.a();
console.log(rst0)
console.log(rst1)
Contract 객체를 만들 때 signer가 아니라 provider를 전달할 수 있는데 signer(Wallet)를 전달하지 않으면 읽기전용입니다.
· 트랜잭션 발생
const ABI = [
'event onEvent1(uint indexed a)',
'event onEvent2(uint a)',
'function getA() view public returns (uint)',
'function a() view public returns (uint)',
'function setA(uint _a) public'
];
const signer = new Wallet(
'0xe6deaed561bbeb9ebc1941b10beb9ff060060d9ea637554abe475eb8f1b13ddc',
provider
)
const contract = new Contract(
'0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0',
ABI,
signer
)
const rst0 = await contract.setA(123);
console.log(rst0)
const rst1 = await contract.a();
console.log(rst1)
{
nonce: 10,
gasPrice: BigNumber { _hex: '0x04a817c800', _isBigNumber: true },
gasLimit: BigNumber { _hex: '0x682c', _isBigNumber: true },
to: '0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0',
value: BigNumber { _hex: '0x00', _isBigNumber: true },
data: '0xee919d50000000000000000000000000000000000000000000000000000000000000007b',
chainId: 1337,
v: 2709,
r: '0x229c8022469d2a4cf0123e10b6b109b038545619db3f861ee28859d1d492fd34',
s: '0x00817868e24ce66cc00ebfbe1f2a86fabba40d43bebafc15f78a73497a02d680',
from: '0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17',
hash: '0xb09ab043d685e55312f95d786c37f81eb8afb70fa8fe9e63894b0dcc96cd76e9',
type: null,
confirmations: 0,
wait: [Function (anonymous)]
}
BigNumber { _hex: '0x7b', _isBigNumber: true }
· 이벤트 수신
contract.on('onEvent1', (a) => {
console.log(a)
})
contract.on('onEvent2', (a) => {
console.log(a)
})
이벤트를 발생하는 함수를 호출하면 각각의 이벤트 리스터를 호출합니다.