npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hardhat-method-prompts

v1.2.0

Published

A hardhat plugin offering the possibility to quickly implement prompt-powered method calls to contracts

Downloads

21

Readme

hardhat-method-prompts

A hardhat plugin offering the possibility to quickly implement prompt-powered method calls to contracts.

Installation

Run this command to install it from NPM:

npm install --save-dev hardhat-common-tools@^1.5.0 hardhat-enquirer-plus@^1.4.2 hardhat-blueprints@^1.2.2 hardhat-method-prompts@^1.2.0

Usage

You'll not typically make use of this package directly, save for developing your own sub-packages or tasks.

If that's the case, then this package allows you to create method calls (which can be static or transactional).

Creating a contract method invocation

Let's say you want to create a mint call for an ERC-1155 contract. You can define your method like this:

const method = new hre.methodPrompts.ContractMethodPrompt(
    "send", "mint", {
        onError: (e) => {
            console.error("There was an error while running this method");
            console.error(e);
        },
        onSuccess: (tx) => {
            console.log("The method ran successfully:", tx);
        }
    }, [{
        name: "to",
        description: "The target of the mint",
        message: "Who will receive the minted tokens?",
        argumentType: "smart-address"
    }, {
        name: "id",
        description: "The ID of the token",
        message: "What's the token you want to mint?",
        argumentType: "uint256"
    }, {
        name: "value",
        description: "The amount of that token",
        message: "What's the amount of the token?",
        argumentType: "uint256"
    }, {
        name: "data",
        description: "The data for the transaction",
        message: "Add some hexadecimal binary data:",
        argumentType: "bytes"
    }], {
        account: {onAbsent: "default"},
        gasPrice: {onAbsent: "prompt"}
    }
);

And then invoking it like this:

await method.invoke(
    // In my case, this is a valid ignition Module#Contract id.
    // If you don't have a specific id, use undefined. It will
    // be prompted to you.
    //
    // Also, feel free to use undfined for deploymentId if you
    // are not interacting with a particular deployment. It will
    // default to `chain-{yourChainId}`.
    deploymentId, "MyOwnedERC1155Module#MyOwnedERC1155",
    {to, id, value: amount, data}, {account, gasPrice}, nonInteractive
);

View methods are simpler, since they do not involve transaction params:

const method = new hre.methodPrompts.ContractMethodPrompt(
    "call", "balanceOf", {
        onError: (e) => {
            console.error("There was an error while running this method");
            console.error(e);
        },
        onSuccess: (value) => {
            console.log("Balance:", value);
        }
    }, [{
        name: "address",
        description: "The target of the mint",
        message: "Who will receive the minted tokens?",
        argumentType: "smart-address"
    }, {
        name: "id",
        description: "The ID of the token",
        message: "What's the token you want to mint?",
        argumentType: "uint256"
    }], {}
);

While the invocation would look like this:

await method.invoke(
    // In my case, this is a valid ignition Module#Contract id.
    // If you don't have a specific id, use undefined. It will
    // be prompted to you.
    //
    // Also, feel free to use undfined for deploymentId if you
    // are not interacting with a particular deployment. It will
    // default to `chain-{yourChainId}`.
    deploymentId, deployedContractId,
    {address, id}, {}, nonInteractive
);

Details about transaction options

The following options can be configured and provided as transaction options:

  1. eip155 can always be specified and must be a boolean.
  2. account can be an account ("0" to "{N-1}", where N is the number of accounts).
  3. value is the amount to pay (e.g. "100000000000000000000000" or "2.5 ether").
  4. gas is an uint256 value with the gas (e.g. "1000000").
  5. gasPrice is the amount to pay per gas unit (e.g. "400000000000" or "400 gwei").
  6. maxFeePerGas the max EIP-1559 amount to pay per gas unit.
  7. maxPriorityFeePerGas the priority EIP-1559 amount to pay per gas unit.

For each of these options (except eip155) each input is a string as received from command line (this is suitable for tasks), but the configuration tolerates {onAbsent: "prompt"}, {onAbsent: "default"} and {onAbsent: "default", "default": someValue}.

The meaning of each setting is as follows:

  • The first one will prompt the user for a value if the value is not provided.
  • The second one will not prompt the user: it will not be included among the final options and will be treated by default (e.g. gasPrice and gas will be estimated, EIP-1559 ones will not be used or estimated, value will be 0, and the account will be the 0th / first one).
  • The third one works similar: it will not prompt on absence but will use the specified default value when determining the final transaction options.

Creating a custom invocation

While the previous ones are calls that were designed for interacting with contracts, you might want to create tasks that are not necessarily related to contracts but with some general or low-level interaction (with a complex, yet single-transaction, set of instructions).

The syntax to do that is similar, yet different in nature. For example, a task to do a balance transfer of native token is not strictly related to a contract's method, but instead a custom callback:

const method2 = new hre.methodPrompts.CustomPrompt(
    function([address], txOpts) {
        return hre.common.transfer(address, txOpts);
    }, {
        onError: (e) => {
            console.error("There was an error while getting the balance");
            console.error(e);
        },
        onSuccess: (tx) => {
            console.log("The transfer ran successfully:", tx);
        }
    }, [{
        name: "address",
        description: "The address (or account index) to send native tokens to",
        message: "What's the address (or account index) to send native tokens to?",
        argumentType: "smart-address"
    }], {
        value: {onAbsent: "prompt"},
        account: {onAbsent: "default"},
        gasPrice: {onAbsent: "default"}
    }
);

// Let's assume address, value, account, gasPrice and nonInteractive literally
// exist and are exactly named like that.
await method2.invoke({address}, {value, account, gasPrice}, nonInteractive);

PLEASE NOTE: The regular arguments are an array that gets its values in order from the specs in a one-to-one relation against the list of regular arguments defined in the prompt. The transaction options are always an object in the same way they're passed to the contract calls.

Registering them as tasks

You can register hardhat tasks quickly, based on these prompt classes. For example:

method.asTask("balance-of", "Gets the native balance of an address");

will create the task: npx hardhat invoke balance-of. Use --help to get the full details. You'll notice how all the arguments for the method are converted into optional task arguments (and all the non-provided arguments will be prompted to the user). Also, arguments for transaction options are also defined there. Finally, the --non-interactive flag is also defined.

You can pass extra options as a third argument:

method.asTask("balance-of", "Gets the native balance of an address", {
  scope: someHardhatScopeHere,
  onlyExplicitTxOptions: true
});

If you specify null into someHardhatScopeHere, then the defined task will belong to no scope at all. If you don't specify a scope there, then a default invoke scope will be used to define the task. Otherwise, the specified scope will be used to define the task.

The onlyExplicitTxOptions flag, when set to True, only allows specifying the explicitly defined transaction options for the task. Otherwise, the options that are not specified are also not included as task arguments. This one should be set to true for methods that would not make use of code that invokes transactions (e.g. balance-of) and, under certain conditions, it might be useful for certain transactional methods.

These options make sense bot for custom and regular method prompts.

The body of the task is not defined by the user: it will become a call to the .invoke method properly (both for custom and regular methods).

Already defined tasks

The following tasks are already defined. Check them with --help to have a grasp on what they do:

# Tools:
npx hardhat invoke keccak256 --help
# Native:
npx hardhat invoke balance-of --help
npx hardhat invoke transfer --help
# ERC-20:
npx hardhat invoke erc20:approve --help
npx hardhat invoke erc20:allowance --help
npx hardhat invoke erc20:balance-of --help
npx hardhat invoke erc20:decimals --help
npx hardhat invoke erc20:name --help
npx hardhat invoke erc20:symbol --help
npx hardhat invoke erc20:total-supply --help
npx hardhat invoke erc20:transfer --help
npx hardhat invoke erc20:transfer-from --help
# ERC-721
npx hardhat invoke erc721:approve --help
npx hardhat invoke erc721:balance-of --help
npx hardhat invoke erc721:get-approved --help
npx hardhat invoke erc721:name --help
npx hardhat invoke erc721:owner-of --help
npx hardhat invoke erc721:safe-transfer-from --help
npx hardhat invoke erc721:safe-transfer-from-with-data --help
npx hardhat invoke erc721:set-approval-for-all --help
npx hardhat invoke erc721:symbol --help
npx hardhat invoke erc721:token-uri --help
npx hardhat invoke erc721:transfer-from --help
# ERC-1155
npx hardhat invoke erc1155:balance-of --help
npx hardhat invoke erc1155:balance-of-batch --help
npx hardhat invoke erc1155:set-approval-for-all --help
npx hardhat invoke erc1155:is-approved-for-all --help
npx hardhat invoke erc1155:safe-transfer-from --help
npx hardhat invoke erc1155:safe-batch-transfer-from --help
npx hardhat invoke erc1155:token-uri --help

An example of the invocations. These assume:

  1. The futures' ids are valid on each --deployment-contract-id.
  2. The ERC-20 contract starts with more than 1e18 token amount on address for account [1].
  3. The ERC-721 contract starts with token 1 for account [1].
  4. The ERC-1155 contract starts with more than 1e18 token amount of token 1 on address for account [1].
  5. The user executes the instructions in strict order as presented.
  6. They can be executed without any argument (save for --network), but the commands will become interactive and prompt each argument to the user.

The instructions are:

// Tools:
npx hardhat invoke keccak256 --text "Hello World"
// Native:
npx hardhat invoke balance-of --address 0 --network localhost --non-interactive
npx hardhat invoke transfer --account 0 --address 1 --value "1 ether" --network localhost --non-interactive
// ERC-20:
npx hardhat invoke erc20:approve --owner 1 --allowed 0 --amount 1000000000000000000 --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --non-interactive
npx hardhat invoke erc20:allowance --owner 1 --allowed 0 --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --non-interactive
npx hardhat invoke erc20:balance-of --address 1 --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --non-interactive
npx hardhat invoke erc20:decimals --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --non-interactive
npx hardhat invoke erc20:name --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --non-interactive
npx hardhat invoke erc20:symbol --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --non-interactive
npx hardhat invoke erc20:total-supply --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --non-interactive
npx hardhat invoke erc20:transfer --to 0 --amount 1000000000000000000 --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --account 1 --non-interactive
npx hardhat invoke erc20:transfer-from --from 1 --to 0 --amount 1000000000000000000 --network localhost --deployed-contract-id "MyOwnedERC20Module#MyOwnedERC20" --account 0 --non-interactive
// ERC-721
npx hardhat invoke erc721:approve --to 0 --token-id 1 --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --account 1 --non-interactive
npx hardhat invoke erc721:balance-of --address 1 --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --non-interactive
npx hardhat invoke erc721:get-approved --token-id 1 --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --non-interactive
npx hardhat invoke erc721:name --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --non-interactive
npx hardhat invoke erc721:owner-of --token-id 1 --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --non-interactive
npx hardhat invoke erc721:safe-transfer-from --from 1 --to 0 --token-id 1 --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --account 1 --non-interactive
npx hardhat invoke erc721:safe-transfer-from-with-data --from 0 --to 1 --data "0x" --token-id 1 --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --account 0 --non-interactive
npx hardhat invoke erc721:set-approval-for-all --address 0 --set true --network localhost --account 1 --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --non-interactive
npx hardhat invoke erc721:symbol --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --non-interactive
npx hardhat invoke erc721:token-uri --token-id 1 --network localhost --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --non-interactive
npx hardhat invoke erc721:transfer-from --from 1 --to 0 --token-id 1 --deployed-contract-id "MyOwnedERC721Module#MyOwnedERC721" --network localhost --account 1 --non-interactive
// ERC-1155
npx hardhat invoke erc1155:balance-of --address 1 --token-id 1 --network localhost --deployed-contract-id "MyOwnedERC1155Module#MyOwnedERC1155" --non-interactive
npx hardhat invoke erc1155:balance-of-batch --addresses "[1]" --token-ids "[1]" --network localhost --deployed-contract-id "MyOwnedERC1155Module#MyOwnedERC1155" --non-interactive
npx hardhat invoke erc1155:set-approval-for-all --address 1 --approve y --network localhost --deployed-contract-id "MyOwnedERC1155Module#MyOwnedERC1155" --non-interactive
npx hardhat invoke erc1155:is-approved-for-all --operator 1 --owner 0 --network localhost --deployed-contract-id "MyOwnedERC1155Module#MyOwnedERC1155" --non-interactive
npx hardhat invoke erc1155:safe-transfer-from --from 1 --to 0 --token-id 1 --amount 1000000000000000000 --data 0x --network localhost --deployed-contract-id "MyOwnedERC1155Module#MyOwnedERC1155" --account 1 --non-interactive
npx hardhat invoke erc1155:safe-batch-transfer-from --from 1 --to 0 --token-ids "[1]" --amounts "[1000000000000000000]" --data 0x --network localhost --deployed-contract-id "MyOwnedERC1155Module#MyOwnedERC1155" --account 1 --non-interactive
npx hardhat invoke erc1155:token-uri --token-id 1 --network localhost --deployed-contract-id "MyOwnedERC1155Module#MyOwnedERC1155" --non-interactive