Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
A library and cli to create a local blockchain for fast Ethereum development.
Features • Getting Started • Documentation • Community • Docker • Contributing • Related
Ganache is an Ethereum simulator that makes developing Ethereum applications faster, easier, and safer. It includes all popular RPC functions and features (like events) and can be run deterministically to make development a breeze.
console.log
in SolidityGanache can be used from the command line, programmatically via Node.js, or in the browser.
You must first install Node.js >= v16.0.0 and npm >= 7.10.0.
To install Ganache globally, run:
$ npm install ganache --global
In case you're upgrading from a previous version of Ganache, we've also written up this handy guide on how to upgrade/install Ganache and to document all breaking changes to look out for.
Once installed globally, you can start ganache right from your command line:
ganache
Your output should look something like this:
Ganache CLI v6.12.1 (ganache-core: 2.13.1)
Available Accounts
==================
(0) 0xe261e26aECcE52b3788Fac9625896FFbc6bb4424 (100 ETH)
(1) 0xcE16e8eb8F4BF2E65BA9536C07E305b912BAFaCF (100 ETH)
(2) 0x02f1c4C93AFEd946Cce5Ad7D34354A150bEfCFcF (100 ETH)
(3) 0x0B75F0b70076Fab3F18F94700Ecaf3B00fE528E7 (100 ETH)
(4) 0x7194d1F1d43c2c58302BB61a224D41B649e65C93 (100 ETH)
(5) 0xC9A2d92c5913eDEAd9a7C936C96631F0F2241063 (100 ETH)
(6) 0xD79BcDE5Cb11cECD1dfC6685B65690bE5b6a611e (100 ETH)
(7) 0xb6D080353f40dEcA2E67108087c356d3A1AfcD64 (100 ETH)
(8) 0x31A064DeeaD74DE7B9453beB4F780416D8859d3b (100 ETH)
(9) 0x37524a360a40C682F201Fb011DB7bbC8c8A247c6 (100 ETH)
Private Keys
==================
(0) 0x7f109a9e3b0d8ecfba9cc23a3614433ce0fa7ddcc80f2a8f10b222179a5a80d6
(1) 0x6ec1f2e7d126a74a1d2ff9e1c5d90b92378c725e506651ff8bb8616a5c724628
(2) 0xb4d7f7e82f61d81c95985771b8abf518f9328d019c36849d4214b5f995d13814
(3) 0x941536648ac10d5734973e94df413c17809d6cc5e24cd11e947e685acfbd12ae
(4) 0x5829cf333ef66b6bdd34950f096cb24e06ef041c5f63e577b4f3362309125863
(5) 0x8fc4bffe2b40b2b7db7fd937736c4575a0925511d7a0a2dfc3274e8c17b41d20
(6) 0xb6c10e2baaeba1fa4a8b73644db4f28f4bf0912cceb6e8959f73bb423c33bd84
(7) 0xfe8875acb38f684b2025d5472445b8e4745705a9e7adc9b0485a05df790df700
(8) 0xbdc6e0a69f2921a78e9af930111334a41d3fab44653c8de0775572c526feea2d
(9) 0x3e215c3d2a59626a669ed04ec1700f36c05c9b216e592f58bbfd3d8aa6ea25f9
HD Wallet
==================
Mnemonic: candy maple velvet cake sugar cream honey rich smooth crumble sweet treat
Base HD Path: m/44'/60'/0'/0/{account_index}
Default Gas Price
==================
20000000000
Gas Limit
==================
6721975
Call Gas Limit
==================
9007199254740991
Listening on 127.0.0.1:8545
If you want to install Ganache into an npm project, run:
$ npm install ganache
You can then add Ganache to your package.json scripts:
"scripts": {
"ganache": "ganache --wallet.seed myCustomSeed"
}
See Documentation for additional command line options.
Then start it:
$ npm run ganache
You can use Ganache programmatically from Node.js. Install Ganache into your npm package:
$ npm install ganache
Then you can use ganache as an EIP-1193 provider only, an EIP-1193 provider and JSON-RPC web server, as a Web3 provider, an ethers provider, or a viem transport.
const ganache = require("ganache");
const options = {};
const provider = ganache.provider(options);
const accounts = await provider.request({ method: "eth_accounts", params: [] });
const ganache = require("ganache");
const options = {};
const server = ganache.server(options);
const PORT = 0; // 0 means any available port
server.listen(PORT, async err => {
if (err) throw err;
console.log(`ganache listening on port ${server.address().port}...`);
const provider = server.provider;
const accounts = await provider.request({
method: "eth_accounts",
params: []
});
});
To use ganache as a Web3 provider:
const Web3 = require("web3");
const ganache = require("ganache");
const web3 = new Web3(ganache.provider());
NOTE: depending on your web3 version, you may need to set a number of confirmation blocks
const web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 });
const ganache = require("ganache");
const provider = new ethers.providers.Web3Provider(ganache.provider());
To use a ganache provider as a viem transport:
import { createWalletClient, custom } from "viem";
import { localhost } from "viem/chains";
import ganache from "ganache";
const client = createWalletClient({
chain: localhost,
transport: custom(ganache.provider())
});
You can also use Ganache in the browser by adding the following script to your HTML:
<script src="https://cdn.jsdelivr.net/npm/ganache@{VERSION}/dist/web/ganache.min.js"></script>
NOTE: the {VERSION}
in the above path needs to be replaced with a version number or tag that is listed in npm.
From there, Ganache is available in your browser for use:
const options = {};
const provider = Ganache.provider(options);
See our Interactive Docs for a full list of Ganache's RPC methods.
The startup options are grouped in the chain
, database
, fork
, logging
, miner
, wallet
, and server
namespaces, and should be used as such on startup, i.e.
ganache --namespace.option="value"
for CLI use, and
const options = { namespace: { option: "value"}};
const provider = ganache.provider(options);
for programmatic use.
The following options are listed for command line use, but can also be used when running Ganache programmatically in your project.
Chain:
--chain.allowUnlimitedContractSize Allows unlimited contract sizes while debugging. Setting this to true
will cause ganache to behave differently than production environments.
[boolean] [default: false]
--chain.allowUnlimitedInitCodeSize Allows unlimited initcode sizes while debugging. Setting this to true
will cause ganache to behave differently than production environments.
[boolean] [default: false]
--chain.asyncRequestProcessing When set to false only one request will be processed at a time.
[boolean] [default: true]
--chain.chainId The currently configured chain id. [number] [default: 1337]
-i, --chain.networkId The id of the network returned by the RPC method net_version.
deprecated aliases: --networkId
[number] [default: System time at process start or
Network ID of forked blockchain if configured.]
-t, --chain.time Date that the first block should start.
deprecated aliases: --time [number]
-k, --chain.hardfork Set the hardfork rules for the EVM.
deprecated aliases: --hardfork
[string] [choices: "constantinople", "byzantium", "petersburg", "istanbul", "muirGlacier", "berlin",
"london", "arrowGlacier", "grayGlacier", "merge", "shanghai"] [default: "shanghai"]
--chain.vmErrorsOnRPCResponse Whether to report runtime errors from EVM code as RPC errors.
[boolean] [default: false]
Database:
--database.dbPath Specify a path to a directory to save the chain database.
deprecated aliases: --db, --db_path [string]
Logging:
--logging.debug Set to true to log EVM opcodes. [boolean] [default: false]
-q, --logging.quiet Set to true to disable logging.
deprecated aliases: --quiet [boolean] [default: false]
-v, --logging.verbose Set to true to log detailed RPC requests.
deprecated aliases: --verbose [boolean] [default: false]
Miner:
-b, --miner.blockTime Sets the blockTime in seconds for automatic mining. A blockTime of 0
enables "instamine mode", where new executable transactions will be
mined instantly.
deprecated aliases: --blockTime [number] [default: 0]
-g, --miner.defaultGasPrice Sets the default gas price in WEI for transactions if not otherwise
specified.
deprecated aliases: --gasPrice [string] [default: 0x77359400]
-l, --miner.blockGasLimit Sets the block gas limit in WEI.
deprecated aliases: --gasLimit [string] [default: 0xb71b00]
--miner.defaultTransactionGasLimit Sets the default transaction gas limit in WEI. Set to "estimate" to
use an estimate (slows down transaction execution by 40%+).
[string] [default: 0x15f90]
--miner.difficulty Sets the block difficulty. [string] [default: 0x1]
--miner.callGasLimit Sets the transaction gas limit in WEI for eth_call and eth_estimateGas
calls.
[string] [default: 0x2faf080]
--miner.instamine Set the instamine mode to either "eager" (default) or "strict". In
"eager" mode a transaction will be included in a block before its hash
is returned to the caller. In "strict" mode a transaction's hash is
returned to the caller before the transaction is included in a block.
This value has no effect if `blockTime` is *not* `0` (the default).`
[string] [choices: "eager", "strict"] [default: "eager"]
--miner.coinbase Sets the address where mining rewards will go.
[default: 0x0000000000000000000000000000000000000000]
--miner.extraData Set the extraData block header field a miner can include.
[string] [default: 0x]
--miner.priceBump Minimum price bump percentage needed to replace a transaction that
already exists in the transaction pool. [string] [default: 10]
Wallet:
--wallet.accounts Account data in the form <private_key>,<initial_balance>, can be
specified multiple times. Note that private keys are 64 characters
long and must be entered as an 0x-prefixed hex string. Balance can
either be input as an integer, or as a 0x-prefixed hex string with
either form specifying the initial balance in wei.
deprecated aliases: --account [array]
-a, --wallet.totalAccounts Number of accounts to generate at startup.
deprecated aliases: --accounts [number] [default: 10]
-d, --wallet.deterministic Use pre-defined, deterministic seed.
deprecated aliases: --deterministic [boolean] [default: false]
-s, --wallet.seed Seed to use to generate a mnemonic.
deprecated aliases: --seed
[string]
[default: Random value, unless wallet.deterministic is specified]
-m, --wallet.mnemonic Use a specific HD wallet mnemonic to generate initial addresses.
deprecated aliases: --mnemonic [string]
[default: Generated from wallet.seed]
-u, --wallet.unlockedAccounts Array of addresses or address indexes specifying which accounts should
be unlocked.
deprecated aliases: --unlock [array]
-n, --wallet.lock Lock available accounts by default (good for third party transaction
signing).
deprecated aliases: --secure, --lock [boolean] [default: false]
--wallet.passphrase Passphrase to use when locking accounts.
deprecated aliases: --passphrase [string]
--wallet.accountKeysPath Specifies a file to save accounts and private keys to, for testing.
deprecated aliases: --account_keys_path, --acctKeys [string]
-e, --wallet.defaultBalance The default account balance, specified in ether.
deprecated aliases: --defaultBalanceEther [number] [default: 1000]
--wallet.hdPath The hierarchical deterministic path to use when generating accounts.
[string] [default: m,44',60',0',0]
Fork:
-f, --fork.url Fork from another currently running Ethereum client at a given block.
Input should be the URL of the node, e.g. "http://localhost:1337". You
can optionally specify the block to fork from using an @ sign:
"http://localhost:1337@8675309".
You can specify Basic Authentication credentials in the URL as well.
e.g., "wss://user:password@example.com/". If you need to use an Infura
Project Secret, you would use it like this:
"wss://:{YOUR-PROJECT-SECRET}@mainnet.infura.com/..."
Alternatively, you can use the fork.username and fork.password
options.
deprecated aliases: --fork
--fork.network A network name to fork from; uses Infura's archive nodes.
Use the shorthand command ganache --fork to automatically fork from
Mainnet at the latest block.
[choices: "mainnet", "goerli", "görli", "sepolia"]
--fork.blockNumber Block number the provider should fork from.
[default: Latest block number]
--fork.preLatestConfirmations When the fork.blockNumber is set to "latest" (default), the number of
blocks before the remote node's "latest" block to fork from.
[number] [default: 5]
--fork.username Username to use for Basic Authentication. Does not require setting
fork.password.
When combined with fork.password, is shorthand for fork: { headers: {
"Authorization": "Basic {ENCODED-BASIC-HEADER}" } }
If the fork.headers option specifies an "Authorization" header, it
will be be inserted after this Basic token.
--fork.password Password to use for Basic Authentication. Does not require setting
fork.username.
When combined with fork.username, is shorthand for fork: { headers: {
"Authorization": "Basic {ENCODED-BASIC-HEADER}" } }
If the fork.headers option specifies an "Authorization" header, it
will be be inserted after this Basic token.
--fork.jwt Encoded JSON Web Token (JWT) used for authenticating to some servers.
Shorthand for fork:
{ headers: { "Authorization": "Bearer {YOUR-ENCODED-JWT}" } }
If the fork.headers option specifies an "Authorization" header, it
will be be inserted after the JWT Bearer token.
--fork.userAgent The User-Agent header sent to the fork on each request.
Sent as Api-User-Agent when used in the browser.
Will be overridden by a "User-Agent" defined in the fork.headers
option, if provided.
[default: Ganache/7.0.0-beta.0
(https://www.trufflesuite.com/ganache; ganache<at>trufflesuite.com)]
--fork.origin The Origin header sent to the fork on each request.
Ignored in the browser.
Will be overridden by an "Origin" value defined in the fork.headers
option, if provided.
--fork.headers Headers to supply on each request to the forked provider.
Headers set here override headers set by other options, unless
otherwise specified.
Defaults to: ["User-Agent: Ganache/VERSION
(https://www.trufflesuite.com/ganache; ganache<at>trufflesuite.com)"]
[array]
--fork.requestsPerSecond Restrict the number of requests per second sent to the fork provider.
0 means no limit is applied. [number] [default: 0]
--fork.disableCache Disables caching of all forking requests. [boolean] [default: false]
--fork.deleteCache Deletes the persistent cache before starting.
[boolean] [default: false]
Server:
--server.ws Enable a websocket server. [boolean] [default: true]
--server.wsBinary Whether or not websockets should response with binary data
(ArrayBuffers) or strings.
[choices: "true", "false", "auto"]
[default: auto]
--server.rpcEndpoint Defines the endpoint route the HTTP and WebSocket servers will listen
on.
[default: "/"]
-h, --server.host Hostname to listen on.
deprecated aliases: --host, --hostname
[string] [default: "127.0.0.1"]
-p, --server.port, --port Port to listen on.
deprecated aliases: --port
[number] [default: 8545]
Ganache can be started as a background instance via the CLI by providing the following argument (along with any valid combination of the Ganache startup arguments above):
-D, --detach, --😈 Run Ganache in detached (daemon) mode. [boolean]
This will start Ganache as a background process, and return to the console as soon as Ganache has started and is ready to
receive requests. A friendly name will be returned to STDOUT which can then be used to interact with the instance via
the ganache instances
command with the following arguments:
Commands:
ganache instances list List instances running in detached mode
ganache instances stop <name> Stop the instance specified by <name>
E.g., start Ganache on port 8544, with a block time of 10 seconds, and then stop the instance.
$ ganache --port=8544 --miner.blockTime=10 --detach
salted_caramel_ganache
$ ganache instances list
┌───────┬────────────────────────┬──────────┬─────────┬────────────────┬────────┐
│ PID │ Name │ Flavor │ Version │ Host │ Uptime │
├───────┼────────────────────────┼──────────┼─────────┼────────────────┼────────┤
│ 12182 │ salted_caramel_ganache │ ethereum │ 7.6.0 │ 127.0.0.1:8545 │ 36s │
└───────┴────────────────────────┴──────────┴─────────┴────────────────┴────────┘
$ ganache instances stop salted_caramel_ganache
Process stopped
With the following command, you can start Ganache, run your tests, and stop Ganache when you are finished.
GANACHE=$(ganache --detach) && npm run test; ganache instances stop $GANACHE
Or if you are running PowerShell on Windows, you can do:
$GANACHE=ganache --detach; npm run test; ganache instances stop $GANACHE
In addition to EIP-1193's "message"
event and the legacy "data"
event, Ganache emits 4 additional events: "ganache:vm:tx:before"
, "ganache:vm:tx:step"
, "ganache:vm:tx:after"
, and "ganache:vm:tx:console.log"
.
These events can be used to observe the lifecycle of any transaction executed via *sendTransaction
, eth_call
, debug_traceTransaction
, or debug_storageRangeAt
.
These share the event paradigm that Truffle uses, but without any of the wildcard handling, i.e., no "vm:*"
support (for now).
Each of these events will emit a context
object which is a unique object that can be used to identify a transaction over the course of its lifecycle. For example:
interface StepEvent {
account: {
nonce: bigint;
balance: bigint;
stateRoot: Buffer;
codeHash: Buffer;
};
address: Buffer;
codeAddress: Buffer;
depth: number;
gasLeft: bigint;
gasRefund: bigint;
memory: Buffer;
memoryWordCount: bigint;
opcode: {
name: string;
fee: number;
};
pc: number;
returnStack: Buffer[];
stack: Buffer[];
}
const contexts = new Map();
provider.on("ganache:vm:tx:before", (event: { context: {} }) => {
contexts.set(event.context, []);
});
provider.on("ganache:vm:tx:step", (event: { context: {}; data: StepEvent }) => {
contexts.get(event.context).push(event.data);
});
provider.on(
"ganache:vm:tx:console.log",
(event: { context: {}; logs: (string | bigint | boolean)[] }) => {
console.log(...event.logs);
}
);
provider.on("ganache:vm:tx:after", (event: { context: {} }) => {
doAThingWithThisTransactionsSteps(contexts.get(event.context));
contexts.delete(event.context);
});
The reason this context
is necessary is that Ganache may run multiple transactions simultaneously, so "ganache:vm:tx:step"
events from different transactions could be intermingled.
The above events will be emitted for eth_call
, *sendTransaction
, debug_traceTransaction
, and debug_storageRangeAt
.
Currently, we do not await the event listener's return value, however, we'll likely enable this in the future.
console.log
in SolidityBy default, Ganache logs to stdout when a contract executes a console.log
Solidity statement during eth_call
, eth_sendTransaction
, personal_sendTransaction
, and eth_sendRawTransaction
.
See the @ganache/console.log package
for implementation and usage.
The simplest way to get started with the Docker image:
$ docker run --detach --publish 8545:8545 trufflesuite/ganache:latest
To pass options to Ganache through Docker simply add the arguments to the end of the run command, e.g.,
$ docker run --detach --publish 8545:8545 trufflesuite/ganache:latest --accounts 10 --debug
^^^^^^^^^^^^^^^^^^^^^
The Docker container adds an environment variable DOCKER=true
; when this variable is set to true
(case insensitive), Ganache uses a default hostname IP of 0.0.0.0
instead of the normal default 127.0.0.1
. You can still specify a custom hostname however:
$ docker run --detach --publish 8545:8545 trufflesuite/ganache:latest --host XXX.XXX.XXX.XXX
^^^^^^^^^^^^^^^^^^^^^^
To build and run the Docker container from source:
$ git clone https://github.com/trufflesuite/ganache.git && cd ganache
then:
$ docker build --tag trufflesuite/ganache --file ./packages/ganache/Dockerfile .
$ docker run --publish 8545:8545 trufflesuite/ganache
See CONTRIBUTING.md for our guide to contributing to Ganache.
FAQs
A library and cli to create a local blockchain for fast Ethereum development.
We found that ganache demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 9 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.