diff --git a/docs/docs/guides/wallet/image.jpeg b/docs/docs/guides/wallet/image.jpeg deleted file mode 100644 index 455abbf9bcf..00000000000 Binary files a/docs/docs/guides/wallet/image.jpeg and /dev/null differ diff --git a/docs/docs/guides/wallet/index.md b/docs/docs/guides/wallet/index.md index 9dd38e750b5..0e8858ad530 100644 --- a/docs/docs/guides/wallet/index.md +++ b/docs/docs/guides/wallet/index.md @@ -1,65 +1,118 @@ --- sidebar_position: 1 -sidebar_label: 'Mastering Wallets & Accounts' +sidebar_label: 'Introduction to Accounts & Wallets' --- -# Wallets and Accounts Overview +# Introduction to Accounts & Wallets +The concept of an [account](https://ethereum.org/en/developers/docs/accounts/) is central to Ethereum and it can be used to refer to two types of entities that are native to Ethereum: externally-owned accounts and contract accounts. This document relates _exclusively_ to **externally-owned accounts**. An externally-owned account is associated with a "[key pair](https://ethereum.org/en/developers/docs/accounts/#externally-owned-accounts-and-key-pairs)", which is a general concept that is related to [public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography). The key pair consists of a private key, which must always be kept secret, and a public key, which is used to derive a public identifier (address) for an account. Ethereum accounts have an [ETH](https://ethereum.org/en/developers/docs/intro-to-ethereum/#eth) balance, which can be [transferred](/guides/wallet/transactions) to other accounts or used to pay for interactions with [smart contracts](/guides/smart_contracts/smart_contracts_guide). Anyone with access to an account's private key has the ability to control that account's ETH balance, so it's important that an account's private key is always kept secret. In addition to the general guidelines for [protecting private keys](https://ethereum.org/en/security/#protect-private-keys/), private keys should never be included in client-side code that can be seen by end users and should never be committed to code repositories. -## Live code editor +In the context of this document, the term "wallet" refers to a collection of accounts and should not be confused with [wallet "applications"](https://ethereum.org/en/wallets/). - +## Accounts -## Introduction +The [`web3-eth-accounts`](/api/web3-eth-accounts) package contains functions to generate Ethereum accounts, sign transactions and data, and more. In Web3.js, the [`Web3Account`](/api/web3-eth-accounts/interface/Web3Account) interface is used to represent an externally-owned account. The following snippet demonstrates using Web3.js to generate a new random account and then using that account to sign a message: -A Web3.js `Wallet` is your main entry point if you want to use a private key directly to do any blockchain operations (transactions), also called `Signer` in other libraries. - -Unlike other libraries where a wallet holds just one account, a Web3.js `Wallet` can handle **multiple accounts**. They each have their private key and address. So, whether those keys are in your computer's memory or protected by MetaMask, the Wallet makes Ethereum tasks secure and simple. - -The `web3-eth-accounts` package contains functions to generate Ethereum accounts and sign transactions and data. - -In Ethereum, a private key is a critical part of the cryptographic key pair used to secure and control ownership of Ethereum addresses. Each Ethereum address has a matching set of public and private keys in a public-key cryptography system. This key pair enables you to own an Ethereum address, manage funds, and initiate transactions. - -Learn more about wallets [here](https://ethereum.org/en/wallets/) - -You can sign and send transactions in different ways. +```js +// generate a new random account +const account = web3.eth.accounts.create(); -- [Local wallet](./local_wallet) **(Highly recommended)** -- [Node Wallet](./node_wallet) **(Deprecated)** +console.log(account); +/* ↳ +{ + address: '0x9E82491d1978217d631a3b467BF912933F54788f', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] +} +*/ -For each of them you can use [Web3PromiEvent](./promi_event) to catch extra transaction's events. +// use the account to sign a message +const signature = account.sign("Hello, Web3.js!"); +/* ↳ +{ + message: 'Hello, Web3.js!', + messageHash: '0xc0f5f7ee704f1473acbb7959f5f925d787a9aa76dccc1b4914cbe77c09fd68d5', + v: '0x1b', + r: '0x129822b685d4404924a595af66c9cdd6367a57c66ac66e2e10fd9915d4772fbd', + s: '0x62db48d6f5e47fe87c64a0991d6d94d23b6024d5d8335348f6686b8c46edb1e9', + signature: '0x129822b685d4404924a595af66c9cdd6367a57c66ac66e2e10fd9915d4772fbd62db48d6f5e47fe87c64a0991d6d94d23b6024d5d8335348f6686b8c46edb1e91b' +} +*/ +``` -## Wallets vs Accounts +Note that many of these values will change each time the code is executed, since a new account is created each time. -An **account** in web3.js is an `object`, it refers to an individual Ethereum address with its associated public and private keys. While a wallet is a higher-level construct for managing multiple accounts, an individual Ethereum address is considered an account. +In addition to generating new random accounts, the Account package can also be used to load an existing account from its private key, as in the following snippet: -```ts title='Create a new account' -const account = web3.eth.accounts.create(); +```js +// load an existing account from its private key +const account = web3.eth.accounts.privateKeyToAccount(""); -console.log(account) -/* ↳ +console.log(account); +/* ↳ { address: '0x9E82491d1978217d631a3b467BF912933F54788f', - privateKey: '0x4651f9c219fc6401fe0b3f82129467c717012287ccb61950d2a8ede0687857ba', + privateKey: '', signTransaction: [Function: signTransaction], sign: [Function: sign], encrypt: [Function: encrypt] } */ + +// use the account to sign a message +const signature = account.sign("Hello, Web3.js!"); +/* ↳ +{ + message: 'Hello, Web3.js!', + messageHash: '0xc0f5f7ee704f1473acbb7959f5f925d787a9aa76dccc1b4914cbe77c09fd68d5', + v: '0x1b', + r: '0x129822b685d4404924a595af66c9cdd6367a57c66ac66e2e10fd9915d4772fbd', + s: '0x62db48d6f5e47fe87c64a0991d6d94d23b6024d5d8335348f6686b8c46edb1e9', + signature: '0x129822b685d4404924a595af66c9cdd6367a57c66ac66e2e10fd9915d4772fbd62db48d6f5e47fe87c64a0991d6d94d23b6024d5d8335348f6686b8c46edb1e91b' +} +*/ ``` -A **wallet** in web3.js is an `array` that holds multiple Ethereum accounts. It provides a convenient way to manage and interact with a collection of accounts. Think of it as a digital wallet that you use to store and organize your various Ethereum addresses. +### Account Methods -```ts title='Create a new wallet' -//create a wallet with `1` random account -const wallet = web3.eth.accounts.wallet.create(1); +The following is a list of [`Accounts`](/libdocs/Accounts) methods in the `web3.eth.accounts` package with descriptions and example usage: + +- [create](/libdocs/Accounts#create) +- [decrypt](/libdocs/Accounts#decrypt) +- [encrypt](/libdocs/Accounts#encrypt) +- [hashMessage](/libdocs/Accounts#hashMessage) +- [parseAndValidatePrivateKey](/libdocs/Accounts#libdocs/Accounts#parseandvalidateprivatekey) +- [privateKeyToAccount](/libdocs/Accounts#privatekeytoaccount) +- [privateKeyToAddress](/libdocs/Accounts#privatekeytoaddress) +- [privateKeyToPublicKey](/libdocs/Accounts#privatekeytopublickey) +- [recover](/libdocs/Accounts#recover) +- [recoverTransaction](/libdocs/Accounts#recovertransaction) +- [sign](/libdocs/Accounts#sign) +- [signTransaction](/libdocs/Accounts#signtransaction) + +## Wallets + +A Web3.js wallet is a collection of accounts and is represented with the [`Wallet`](/api/web3-eth-accounts/class/Wallet) class. When a wallet is used to track an account, that account is added to an internal context (i.e. [`Web3Context`](/api/web3-core/class/Web3Context/)), which makes it easier to use that account in the future - this is described in more detail in the [transactions tutorial](/guides/wallet/transactions). The following snippet demonstrates creating a wallet with 2 new random accounts and using the second account to sign a message: + +```js +// create a wallet with 2 new random accounts +const wallet = web3.eth.accounts.wallet.create(2); console.log(wallet) -/* ↳ -Wallet(1) [ +/* ↳ +Wallet(2) [ + { + address: '0xaaD0d33dc9800258c1265bdDA47b9266472144F7', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] + }, { - address: '0xB2D5647C03F36cA54f7d783b6Fa5afED297330d4', - privateKey: '0x7b907534ec13b19c67c2a738fdaa69014298c71f2221d7e5dec280232e996610', + address: '0x359caa845324802C64B97544460F31fba4f9B9ba', + privateKey: '', signTransaction: [Function: signTransaction], sign: [Function: sign], encrypt: [Function: encrypt] @@ -69,133 +122,166 @@ Wallet(1) [ privateKeyToAccount: [Function: privateKeyToAccountWithContext], decrypt: [Function: decryptWithContext] }, - _addressMap: Map(1) { '0xb2d5647c03f36ca54f7d783b6fa5afed297330d4' => 0 }, + _addressMap: Map(2) { + '0xaad0d33dc9800258c1265bdda47b9266472144f7' => 0, + '0x359caa845324802c64b97544460f31fba4f9b9ba' => 1 + }, _defaultKeyName: 'web3js_wallet' ] */ -``` - -## Diagram - -![Diagram wallet and accounts](image.jpeg) - -To learn more about the `accounts` methods, please visit [web3.js accounts API](/libdocs/Accounts) - -To learn more about the `wallet` methods, please visit [web3.js wallet API](/libdocs/Wallet) - -## Sending transactions - -The shortest way to do this, is by creating a `Wallet` directly by adding a private key (the private key must start with '0x' and it must have funds to execute the transaction) - -```ts title='Sending a transaction adding a privateKey' -import { Web3 } from 'web3'; - -const web3 = new Web3('https://ethereum-sepolia.publicnode.com'); -//this will create an array `Wallet` with 1 account with this privateKey -//it will generate automatically a public key for it -//make sure you have funds in this accounts -//highlight-next-line -const wallet = web3.eth.accounts.wallet.add('0x152c39c430806985e4dc16fa1d7d87f90a7a1d0a6b3f17efe5158086815652e5'); - -const _to = '0xc7203efeb54846c149f2c79b715a8927f7334e74'; -const _value = '1'; //1 wei - -//the `from` address in the transaction must match the address stored in our `Wallet` array -//that's why we explicitly access it using `wallet[0].address` to ensure accuracy -const receipt = await web3.eth.sendTransaction({ - from: wallet[0].address, - to: _to, - value: _value, -}); -//if you have more than 1 account, you can change the address by accessing to another account -//e.g, `from: wallet[1].address` - -console.log('Tx receipt:', receipt); +// use the second account in the wallet to sign a message +const signature = wallet[1].sign("Hello, Web3.js!"); +// wallet accounts can also be accessed with the "at" and "get" methods +// wallet.at(1).sign("Hello, Web3.js!") +// wallet.get(1).sign("Hello, Web3.js!") +console.log(signature); /* ↳ -Tx receipt: { - blockHash: '0xa43b43b6e13ba47f2283b4afc15271ba07d1bba0430bd0c430f770ba7c98d054', - blockNumber: 4960689n, - cumulativeGasUsed: 7055436n, - effectiveGasPrice: 51964659212n, - from: '0xa3286628134bad128faeef82f44e99aa64085c94', - gasUsed: 21000n, - logs: [], - logsBloom: '0x00000...00000000', - status: 1n, - to: '0xc7203efeb54846c149f2c79b715a8927f7334e74', - transactionHash: '0xb88f3f300f1a168beb3a687abc2d14c389ac9709f18b768c90792c7faef0de7c', - transactionIndex: 41n, - type: 2n +{ + message: 'Hello, Web3.js!', + messageHash: '0xc0f5f7ee704f1473acbb7959f5f925d787a9aa76dccc1b4914cbe77c09fd68d5', + v: '0x1c', + r: '0xd90fc42ff83fdf0ec6778c1c27f3051439de7844eacf06195c761fece19ed77d', + s: '0x729693156c48d07df9f4970772049dbe24ebce979765f788974a13c318b2834a', + signature: '0xd90fc42ff83fdf0ec6778c1c27f3051439de7844eacf06195c761fece19ed77d729693156c48d07df9f4970772049dbe24ebce979765f788974a13c318b2834a1c' } */ ``` -## Interacting with contracts - -### Writing functions +Note that many of these values will change each time the code is executed, since new accounts are created each time. -To interact with functions that modify or update data in smart contracts(writing-functions), we need to create a `Wallet`. This `Wallet` must holds at least 1 account with the necessary funds to execute these operations on the blockchain. +In addition to generating new random accounts, a wallet can also be used to load an existing account from its private key, as in the following snippet: -```ts title='Interacting with writing-functions of a smart contract' -import { Web3 } from 'web3'; +```js +// create a wallet with a single existing account +const wallet = web3.eth.accounts.wallet.add(""); -const web3 = new Web3('https://ethereum-sepolia.publicnode.com'); - -//create a wallet -//highlight-next-line -const wallet = web3.eth.accounts.wallet.add('0x152c39c430806985e4dc16fa1d7d87f90a7a1d0a6b3f17efe5158086815652e5'); - -//this is how we can access to the first account of the wallet -console.log('Account 1:', wallet[0]); +console.log(wallet); /* ↳ -Account 1: { - address: '0x57CaabD59a5436F0F1b2B191b1d070e58E6449AE', - privateKey: '0x152c39c430806985e4dc16fa1d7d87f90a7a1d0a6b3f17efe5158086815652e5', - ... -} +Wallet(1) [ + { + address: '0xC978F87516152f542dc4D6f64C810B0c206b11A8', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] + }, + _accountProvider: { + create: [Function: createWithContext], + privateKeyToAccount: [Function: privateKeyToAccountWithContext], + decrypt: [Function: decryptWithContext] + }, + _addressMap: Map(1) { '0xc978f87516152f542dc4d6f64c810b0c206b11a8' => 0 }, + _defaultKeyName: 'web3js_wallet' +] */ +``` -//instantiate the contract -const myContract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS); +New accounts can be added to an existing wallet, as is demonstrated by the following code snippet: -//interact with the contract -//wallet[0].address == '0x57CaabD59a5436F0F1b2B191b1d070e58E6449AE' -//highlight-next-line -const txReceipt = await myContract.methods.doSomething().send({ from: wallet[0].address }); +```js +// create a wallet with a single random accounts +const wallet = web3.eth.accounts.wallet.create(1); -console.log('Transaction receipt:', txReceipt); +console.log(wallet); /* ↳ - Transaction receipt: {...} +Wallet(1) [ + { + address: '0x6680D50C2165e8F1841D9CdaA42C2F1b949a39f2', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] + }, + _accountProvider: { + create: [Function: createWithContext], + privateKeyToAccount: [Function: privateKeyToAccountWithContext], + decrypt: [Function: decryptWithContext] + }, + _addressMap: Map(1) { '0x6680d50c2165e8f1841d9cdaa42c2f1b949a39f2' => 0 }, + _defaultKeyName: 'web3js_wallet' +] */ -``` - -### Reading functions (view) - -To interact with smart contracts `view public/external returns`, we don't need to instantiate a `Wallet`, we can do it just by instantiating the smart contract and the provider. -```ts title='Interacting with reading-functions of a smart contract' -import { Web3 } from 'web3'; +// add a new account to the wallet with the wallet's "create" method +wallet.create(1); -//instantiate the provider -const web3 = new Web3('https://ethereum-sepolia.publicnode.com'); - -//instantiate the contract -const myContract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS); +console.log(wallet); +/* ↳ +Wallet(2) [ + { + address: '0x6680D50C2165e8F1841D9CdaA42C2F1b949a39f2', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] + }, + { + address: '0x5eD8a3ED6Bb1f32e4B479380cFAcf43C49a5440A', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] + }, + _accountProvider: { + create: [Function: createWithContext], + privateKeyToAccount: [Function: privateKeyToAccountWithContext], + decrypt: [Function: decryptWithContext] + }, + _addressMap: Map(2) { + '0x6680d50c2165e8f1841d9cdaa42c2f1b949a39f2' => 0, + '0x5ed8a3ed6bb1f32e4b479380cfacf43c49a5440a' => 1 + }, + _defaultKeyName: 'web3js_wallet' +] +*/ -//call the `view function` in the contract -//highlight-next-line -const result = await myContract.methods.doSomething().call(); +// create a new account and add it to the wallet +const newAccount = web3.eth.accounts.create(); +wallet.add(newAccount); -console.log('Result:', result) +console.log(wallet); /* ↳ - Result: ... +Wallet(3) [ + { + address: '0x6680D50C2165e8F1841D9CdaA42C2F1b949a39f2', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] + }, + { + address: '0x5eD8a3ED6Bb1f32e4B479380cFAcf43C49a5440A', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] + }, + { + address: '0x3065Cf410Bd6A10c5FF3Df8f60b82fF5Ee5db18a', + privateKey: '', + signTransaction: [Function: signTransaction], + sign: [Function: sign], + encrypt: [Function: encrypt] + }, + _accountProvider: { + create: [Function: createWithContext], + privateKeyToAccount: [Function: privateKeyToAccountWithContext], + decrypt: [Function: decryptWithContext] + }, + _addressMap: Map(3) { + '0x6680d50c2165e8f1841d9cdaa42c2f1b949a39f2' => 0, + '0x5ed8a3ed6bb1f32e4b479380cfacf43c49a5440a' => 1, + '0x3065cf410bd6a10c5ff3df8f60b82ff5ee5db18a' => 2 + }, + _defaultKeyName: 'web3js_wallet' +] */ ``` -## Wallet methods +### Wallet Methods -The following is a list of `Wallet` [methods](/libdocs/Wallet) in the `web3.eth.accounts.wallet` package with description and example usage: +The following is a list of [`Wallet`](/libdocs/Wallet) methods in the `web3.eth.accounts.wallet` package with description and example usage: - [add](/libdocs/Wallet#add) - [clear](/libdocs/Wallet#clear) @@ -208,20 +294,10 @@ The following is a list of `Wallet` [methods](/libdocs/Wallet) in the `web3.eth. - [save](/libdocs/Wallet#save) - [getStorage](/libdocs/Wallet#getStorage) -## Account methods - -The following is a list of `Accounts` [methods](/libdocs/Wallet) in the `web3.eth.accounts` package with description and example usage: +## Next Steps -- [create](/libdocs/Accounts#create) -- [decrypt](/libdocs/Accounts#decrypt) -- [encrypt](/libdocs/Accounts#encrypt) -- [hashMessage](/libdocs/Accounts#hashMessage) -- [parseAndValidatePrivateKey](/libdocs/Accounts#libdocs/Accounts#parseandvalidateprivatekey) -- [privateKeyToAccount](/libdocs/Accounts#privatekeytoaccount) -- [privateKeyToAddress](/libdocs/Accounts#privatekeytoaddress) -- [privateKeyToPublicKey](/libdocs/Accounts#privatekeytopublickey) -- [recover](/libdocs/Accounts#recover) -- [recoverTransaction](/libdocs/Accounts#recovertransaction) -- [sign](/libdocs/Accounts#sign) -- [signTransaction](/libdocs/Accounts#signtransaction) +This document is just an introduction to Web3.js accounts and wallets. Here are some suggestions for what to review next: +- Learn how to [transfer ETH](/guides/wallet/transactions) from one account to another. +- Build a front-end application that uses [injected accounts](/guides/wallet/metamask) from the MetaMask wallet. +- Use an account to [deploy and interact with a smart contract](/guides/smart_contracts/smart_contracts_guide).