Git Product home page Git Product logo

hashgraph-venin-js's Introduction

Important sunsetting notice πŸŒ‡

This project is no longer maintained. If you wish to develop on the hedera network, please look at the official JS hedera-sdk. Thank you for all your support and interest. It was a good run! πŸ‘‹

Hashgraph Venin JS

NodeJS/JsDOM/Browser tests codecov

Discord support channel contributions license

node version npm version

NPM

Write Web3 Hedera smart-contract dApps frictionless and with ease, without having to deal with the hustle and bustle of Hedera's verbose, underlying services.

Disclaimer: This project is not an official Hedera project and, as such, it is not affiliated with it in any way, shape or form. It is an independent, community driven, effort to bring clarity and joy to developing decentralized apps (dApps) on the Hedera network-chain ecosystem.

Note: Please keep in mind that, although core features are extensively tested and appear to be working, this is still currently under heavy-active development and, as such, we don't recommend this just yet for production use. The API is also very likely to change before we reach there!

Having said that, we will continue to use it "as is" in production even at this initial stage just because we can and are quick to solve any issues that we might encounter.

Features

Venin already is packed with a lot of stuff:
βœ”οΈ Compile a Solidity contract to obtain its Hedera accepted ABI directly from within the library (no external compiler required)
βœ”οΈ Deploy a contract to the network
βœ”οΈ Use a fluent API to interact with deployed, live entities such as contracts
βœ”οΈ Pubsub for contract emitted events
βœ”οΈ Pubsub for transaction receipts
βœ”οΈ Fine grained cost-control
βœ”οΈ Browser bundle-able via a custom made Rollup plugin (webpack pending)
βœ”οΈ Using Hedera File Storage as a place to store generic files and JSONs
βœ”οΈ Create token via the Hedera Token Service (HTS)
βœ”οΈ Create a Hedera account
βœ”οΈ Ready to be plugged into a web3 wallet (aka HIP-338 supported)
βœ”οΈ End to end tested, high coverage (targeting a minimum of 85%) sourcing multiple contracts for the test-base from places such as solidity-by-example and the hedera-sdk-js repo

... with more planned for development:

πŸ”² Better integration of entities across the code-base
πŸ”² Pubsub mechanics for Hedera's Consensus Service
πŸ”² Other account operations
πŸ”² Better error reporting
πŸ”² Increase logging support

... and even more to follow.

The drive

As any good-striving, long-lasting, endeavour, we are using Venin to hopefully fuel everything that we, here at BuiDler Labs, build on Hedera. Our Hedera portfolio currently consists of:

We're basically eating our own dog food. That way, we can hopefully prove that it's something delicious or, if not, we have a good incentive to make it so. This also makes it a good reason to not have it as a "shot and forget" kind of effort.

We will support this for as long as we're going to build on Hedera and, if there's community interest, even beyond that.

Documentation

You can find the API docs here.

We do offer Live Editor functionality where you can give a go to the samples we have prepared.

Another option would be to just code in-browser using our playground

Quick start

  1. Create an .env file at the root of your repo with the following content filled in accordingly (see .env.sample for more details and options):
HEDERAS_NETWORK=testnet
HEDERAS_OPERATOR_ID=0.0...
HEDERAS_OPERATOR_KEY=...
  1. Create a contracts folder in which you add your hello_world.sol solidity contract definition:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract HelloWorld {
    string public greet = "Hello Hashgraph Venin!";
}
  1. Upload and run your contract with the following code:
const { session } = await ApiSession.default();
const helloWorldContract = await Contract.newFrom({
  path: "./hello_world.sol",
});
const liveContract = await session.upload(helloWorldContract);

console.log(await liveContract.greet());

If all goes well, you should see the expected Hello Hashgraph Venin! logged inside your console signifying that the contract was successfully compiled, uploaded and executed.

Also, if you want a quick play-through a similar example, please have a look at our minimum-working code repo.

Testing it

Have the .env file ready (see above) and run

$ npm test

Note: If you're targeting an official network such as a testnet or a previewnet, there will be a cost involved in running the library tests that has to do with API usage regarding contract deployments and execution (among other things). There's also the option of a customnet targeting a self-hosted hedera-service deployment. If you want to go down that path (recommended especially if you are planning to contribute), please follow these instructions.

Contributions

Do you think we missed anything? Want some feature badly? Do you have an idea of something that we might improve? Head over to our issues page and let us know! We want Venin to be a community-lead initiative. This means that any opinion or critic is encouraged (and even welcomed)!

Of course, if you're eager to write it yourself, that's also fine and dandy! Just fork us, add your changes and open a pull request. We'll take it from there ...

Oh! And if you ever feel like talking to us, you can reach us on discord. We're ΓΌber friendly! πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦

License

This work has been published under the MIT License.

hashgraph-venin-js's People

Contributors

3nigma avatar victorholo avatar vla-dev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

kaikookpk12

hashgraph-venin-js's Issues

Wall of text listed at INSUFFICIENT_GAS contract-create failure

It looks like if you're uploading a contract with insufficient gas, you get a wall-of-text printed on CLI:

StatusError: receipt for transaction [email protected] contained error status INSUFFICIENT_GAS
/home/vic/projects/3vs/headstarter-contracts/node_modules/solc/soljson.js:1
null;var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_
...

RuntimeError: abort(StatusError: receipt for transaction [email protected] contained error status INSUFFICIENT_GAS). Build with -s ASSERTIONS=1 for more info.
    at process.abort (/home/vic/projects/3vs/headstarter-contracts/node_modules/solc/soljson.js:1:13012)
    at process.emit (node:events:527:28)
    at emit (node:internal/process/promises:140:20)
    at processPromiseRejections (node:internal/process/promises:274:27)
    at processTicksAndRejections (node:internal/process/task_queues:97:32)

Node.js v17.8.0

It very much looks like the huge chunk of text is the solidity compiler itself.

We need to not let this happen and protect the developer's CLI from 25MB of non-sensical gibberish.

The problem might also be in the hedera SDK itself. We don't know that for sure.

Fix Jest's coverage reporting

As part of our dependency tree, we have the babel-plugin-istanbul package which conflicts with Jest's coveragePathIgnorePatterns as their documentation states.

Basically, this prop gets ignored and everything gets included in the coverage report like so:
image
We need to find a way to bypass this and have proper coverage reporting provided.

Single `bytes` return values are hex-string encoded

If we're returning a single bytes variant from a solidity smart contract (eg. bytes32), Strato returns back to the caller the hex-string encoding of the result (eg. '0x23a0...'). We need it to return the actual array of bytes (Uint8Array).

Example of such function (taken from solidity-by-example>signature code):

function getEthSignedMessageHash(bytes32 _messageHash)
        public
        pure
        returns (bytes32)
    {
        return
            keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)
            );
    }

Move ContractRegistry to ApiSession

This will make the ContractRegistry a session-dependent entity even though it won't be a LiveEntity.

And while we are here, move ApiSession.getLiveContract to the associated ApiSession.ContractRegistry instance.

This will allow more fluent calls such as session.contractRegistry[<name_of_loaded_contract>].getLiveAt({ id }).

Special considerations should be thought for web-runtime contexts. Specifically, the strato-rollup plugin will need to be updated.

We should do this after #33 but lets start discussing it: How will the resulting API be like? Any concerns?

Poll smart-contract transaction logs directly from the REST Mirror Network

Currently, we issue a TransactionRecordQuery request if we want smart-contract execution logs following a ContractExecuteTransaction call. For ContractCallQuery there is no such requirement since, by design, the ContractCallQuery response (which is a ContractFunctionResult) contains those logs.

Such a transaction is costly but there is a way around this: we poll for the logs from the mirror-node via GET-ing on /api/v1/contract/{contractId}/results/logs.

Now this is admittedly a burdensome strategy since it will put load on the mirror-node, yet since other libraries are doing it (eg. hethers), we might as well go down this path for cost-efficiency. Maybe we have this polling enabled via a flag? That's worth thinking about.

Support Hedera Consensus Service

Hedera Consensus Service (HCS) is made out of topics which means that this will most likely be a CreatableEntity variant to allow for session.create(topic) operations.

Add transaction multi-signature support

ApiSession.execute should allow transactions to be signed by multiple Signers before being dispatched to the network.

This only will need to be carried out for Transactions through their Transaction.signWithSigner(signer) method since Querys don't require or support this multi-signature support.

This also means that we will only support HIP-338 compatible Signers for this feature.

We need to provide the ApiSession instance with a default list of Signers so that all Transactions dispatched through that instance's ApiSession.execute are implicitly signed through those Signers before dispatching.

In case of LiveContracts we also need to provide meta-arguments to allow signer overrides or ad-hoc usage that bypass the ApiSession default lists.

Let's discuss the specifics of this feature on this thread.

Pull Strato Rollup plugin into its own package

Following #22 , we will be adding code to support bundling with rollup. This will put some more dependencies (mostly rollup core + plugins) into strato's package.json dependencies list.

These are:

  • rollup
  • @rollup/plugin-commonjs
  • @rollup/plugin-node-resolve
  • @rollup/plugin-json
  • rollup-plugin-node-polyfills
  • rollup-plugin-web-worker-loader
  • magic-string

That's acceptable for now, but if we plan to support multiple bundlers (eg. webpack), we need to pull those out and have them distributed as a separate package (eg. @buidlerlabs/hedera-strato-rollup).

Be careful to move these back in devDependencies when this will wrap up to allow rollup bundlers (such as for docs and the ones used for testing) still work.

Further streamline only-receipt result-types for live-contract executions

Following #48 , we added increased cost-control for LiveContract dynamically binded ABI entities (eg. methods).

From an UX standpoint, there is no point in returning only the receipt for non-mutating (ContractCallQuerys) calls. The dev should be all the time interested in the query result in this case since the state of the contract will never change under these circumstances.

Are there other dev flows that we could improve for only-receipts execution?

LiveContracts should expose LiveEntity operations on a different level

To avoid name clashes due to dynamically binding the ABI methods on the LiveContract instance, we should expose/elevate the LiveEntity operations on a different level. The naming of it remains to be discussed, but it will have to be something like LiveContract.self.deleteEntity() (note the self part).

This will allow to rename the LiveEntity operations into something lighter such as LiveContract.self.delete().

Create Rollup plugin for Strato bundling

The plugin should generate and make available a ContractRegistry object for browser dApp consumption.

ContractRegistry will be a JS object having the keys taking the name of the contracts to use with their coresponding value its ABI in a Human-Readable format.

Eg. for a SimpleStorage contract, you would have ContractRegistry be:

{
  "SimpleStorage" : [ 
    "function get() view returns (uint256)",
    "function num() view returns (uint256)",
    "function set(uint256 _num)" 
  ]
}

This will then allow to instantiate, in browser, LiveContracts without the need to compile the source code.
Eg:

await session.getLiveContract({ id, abi: ContractRegistry.SimpleStorage })

The plugin should be configurable via an options object containing, for now, a includeCompiler boolean (default false) which, when set to true, will allow for contract-compilation (via methods such as Contract.newFrom({ code })) in browser.

Note: When updating the docs, make sure to specify that including the compiler is a bandwidth intensive operation. The browser will have to download more then 20+MB.

Implement `ApiSession.getLiveFile`

Similar to ApiSession.getLiveJson or ApiSession.getLiveContract, this is needed to retrieve a generically hosted, LiveFile, content (string or binary) from the network.

`solc.compile` is not a function

import { Contract } from '@buidlerlabs/hedera-strato-js';

await Contract.newFrom({ path: './hello.sol' });

should work in a pure node-js ESM runtime environment but it does not. It throws a

TypeError: solc.compile is not a function
    at Function.compile (.../node_modules/@buidlerlabs/hedera-strato-js/lib.esm/SolidityCompiler.mjs:78:17)

error.

Other runtime-environments/module resolution mechanics (eg. node-js/require and web/imports) should work.

Reported on 0.7.5

Align `package.json` export strategies with `@hashgprah/sdk`'s

Currently, we are using runtime export matchers (eg. node) to differentiate between esm and cjs servings. The @hashgraph/sdk uses syntactic export matchers (eg 'import/require`).

We need to have Strato use the same package.json export strategy as Hedera if we want to avoid potential hard-to-debug issues such as mismatch class finger-printing (failing of instanceof calls within the sdk, for instance).

Move docs to their own repo

Once we release the Strato Rollup Plugin we are ready to extract the docs (and their lib.docs sources + package.json dependencies) and host them on a separate branch. That way, we'll lighten up the main branch a bit (or maybe a lot?).

Improve error-response handling/reporting

hedera-services's v0.26 has brought the capacity to throw require messages out of smart contract executions. Here is a transaction that has such an error thrown inside its error_message property.

We need to support this!

Ether's interface.decodeErrorResult should be used to parse the error message.

We need to discuss further mechanics:

  • should we wrap the error-message into a custom-error built class before throwing?
  • is the try/catch mechanism sufficient to get this error across to dev-land?

`Contract.allFrom` abstract solidity contracts

Permit loading of abstract contracts even though, by default, this won't result in any byteCode being generated by the Solidity compiler.

So, for example, the following solidity contract:

abstract contract SimpleStorage {
    uint public num;

    function set(uint _num) public {
        num = _num;
    }

    function get() public view returns (uint) {
        return num;
    }
}

even though all of its methods have an implementation, will result in its solo.evm.bytecode.object being ''. Even though it will correctly extract the ABI.

We are allowing this mostly so that the ContractRegistry is able to get generated correctly when bundling (it only needs the ABI in this scenario).

When this is the case, be sure not to allow uploading of the Contract through a ApiSession in an attempt to make it live.

React-native support

I think this will be a beast to tackle, but it would be amazing if we could do it: make strato work in a react-native runtime environment.

Be sure to thoroughly document this journey.

Contract bytes params should be arrayified

Currently, if we are calling a live contract function that has any type of bytes argument, we do not apply arrayify which is available in @ethersproject/bytes which we already have in the project as part of the @ethersproject/abi package.

For example, if we have a hex string (eg. merkle tree root) which we we want to send to a function containing a bytes32 argument, the function call will fail as hedera-sdk-js will expect to always receive a Uint8Array with a length of 32.

Allow library-dependent code linking

We have the following solidity contract as part of our solidity-by-example test group:

library Array {
    function remove(uint[] storage arr, uint index) public {
        // Move the last element into the place to delete
        require(arr.length > 0, "Can't remove from empty array");
        arr[index] = arr[arr.length - 1];
        arr.pop();
    }
}

contract TestArray {
    using Array for uint[];

    uint[] public arr;

    function testArrayRemove() public {
        for (uint i = 0; i < 3; i++) {
            arr.push(i);
        }

        arr.remove(1);

        assert(arr.length == 2);
        assert(arr[0] == 0);
        assert(arr[1] == 2);
    }
}

When compiling the TestArray contract, Solidity does not expand the dependent Array library in the resulting byte-code:
image
which fails Contract instantiation.

`ContractRegistry` is not able to load deep-nested solidity files

When bundling Strato with Rollup, there is an option to recurse (contracts.recurse) which, when set to true, it should recursively load all the solidity files from all directory levels found at contracts.path.

It does not work: The generated ContractRegistry maintains a flatten <contract name>: <contract ABI> reference from all processed solidity files. This means that if there's a contract A located in a.sol and a contract A located at b/a.sol, there will be 2 entries with the same key in ContractRegistry:

{
  A: <a.sol A contract ABI>,
  A: <b/a.sol A contract ABI>
}

which is an invalid state.

The correct prop names should come close to the ones present in #33 :

{
  A: <a.sol A contract ABI>,
  b/A: <b/a.sol A contract ABI>
}

Note: The props currently don't contain the name of the solidity file itself (as present in #33 's description) . This means that if, for the above example, there were also a contract A present in b/c.sol, you would again hit the same name conflict issue. We will resolve this on a separate ticket.

Relax `ApiSession.execute` to allow for only-receipt returns on contract-requests

Currently, ApiSession.execute supports 3 return types:

  • TypeOfExecutionReturn.Receipt
  • TypeOfExecutionReturn.Record
  • TypeOfExecutionReturn.Result

Regardless of the return type selected, if Executable is a contract transaction (ContractCallQuery or ContractExecuteTransaction) a costly TransactionRecordQuery is emitted.

We will add a 4th type, TypeOfExecutionReturn.OnlyReceipt, which will only return receipts without doing other operations that cost crypto.

We will add control logic to LiveContract calls to via a new meta-argument called onlyReceipt (boolean) to only return receipts without doing other operations that cost crypto if desired. This shall also be accomplished by a new session default called onlyReceiptsFromContractRequests with its associated environment value of HEDERAS_DEFAULT_CONTRACT_REQUESTS_RETURN_ONLY_RECEIPTS (boolean, default true).

Use `ethers` > `Interface.encodeFunctionData` when encoding function-parameters

The SDK does not support calling smart-contract methods with complex data-structures such as the storeGroup method from the following listing:

// Source: https://discordapp.com/channels/373889138199494658/909532351388864542/967985376037859329 (community post on hedera#smart-contracts)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract GroupStore {
  struct Group {
    uint8 groupId;
    string groupName;
    Member[] members;
  }

  struct Member {
    uint8 memberId;
    string memberName;
  }

  function storeGroup(Group[] memory _groups) public pure returns (Group[] memory) {
    return _groups;
  }
}

To make this possible, we would have to encode the calling of the function along with its parameters through ether's Interface.encodeFunctionData method and attach the hex-encoded result to the request via setFunctionParameters. Something like this in LiveContract.createContractRequestFor:

const encodedFuncParams = this.interface
  .encodeFunctionData(fDescription.name, args)
  .slice(2);
const funcParamsBuffer = Buffer.from(encodedFuncParams, "hex");

request.setFunctionParameters(funcParamsBuffer);

which will need to replace/augment:

request.setFunction(
  fDescription.name,
  await ContractFunctionParameters.newFor(fDescription, args)
);

Note: We already use ethers on the receiving end to decode/parse the function result (via Interface.decodeFunctionResult)

P.S.: Add the following test and make sure it is working after this gets implemented:

it("calling a live-contract function with complex nested object parameters should be permitted", async () => {
  const { liveContract } = await load("group_store");
  const groups = [
    {
      groupId: 1,
      groupName: "lighters",
      members: [
        {
          memberId: 2,
          memberName: "Luke",
        },
        {
          memberId: 3,
          memberName: "Obi One",
        },
      ],
    },
    {
      groupId: 2,
      groupName: "darkers",
      members: [
        {
          memberId: 5,
          memberName: "Vader",
        },
      ],
    },
  ];

  await expect(liveContract.storeGroup(groups)).resolves.toEqual(groups);
});

Don't forget to cleanup ContractFunctionParameters once done.

Auto-map Hedera's `xxxId` to `address` type arguments when calling live-contracts

Having a contract such as:

contract Bar {
    function foo(address addr) external pure returns (address) {
        return addr;
    }
}

should allow pseudo-code callings such as liveContract.foo(ContractId | AccountId | TokenId | ... ).

Which would end up using the <ContractId | AccountId | TokenId | ... >.toSolidityAddress() as the address addr argument.

Basically, we should look at all the types of Hedera Ids and auto-map, through this principle, every type that has a .toSolidityAddress() function.

Optimize docs page for chat app preview

When embedding the docs link ( https://hsj-docs.buidlerlabs.com/ ) to a messenger app such as skype, the resulting render contains code that should not be present there and replaced with something more SEO friendly.

image

To fix this, we would end up moving the both the OperatorId and the OperatorNetwork react components and refactor them somewhere else. This needs addressing in any way since that part is duplicated between introduction.md and playground.md.

Support chaining of live-contract types

Given the following solidity file:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract Square {
  uint public size;

  constructor(uint _size) payable {
    size = _size;
  }
}

contract SquareCreator {
  function create(uint _size) public returns (Square Square_) {
    return new Square(_size);
  }
}

it would be nice if we would support doing this:

const liveSquare = await squareCreatorLiveContract.create(10);

console.log(await liveSquare.size());

This will allow chaining contract type calls which will further stream-line the development experience.

To make this working, we need a way to understand that a method return type is an actual contract. @ethersproject/abi's Interface does not provide too much help in this regards:
image
even though the solidity compiler does appear to export more info regarding the raw internalType of the output:
image

One way to avoid this is to try and have a naming convention in place similar to the one present in the above example where we could say that 'if a returned variable name ends with an underscore, then try to map its address to a live-contract and return that'. If we go on this path, we need to settle on this convention. For flexibility reasons, It would be nice if we could avoid enforcing this convention and take advantage of solidity's internalType.

Another issue that needs to be addressed for this feature to be implemented is the parser's access to the ABIs for which the resulting live-contracts are built. Basically, in our previous example case, this is the equivalent to answering the question of how to make available the Square ABI to the create result mapper. What happens if the returned contract type is not part of the same solidity file (eg. import path)?

This feature should be flagged by a context config-parameter.

Implement `ApiSession.getLiveTopic`

We need a way to lock onto an existing LiveTopic so that we can interact with it cross-ApiSession. This shall be done in a similar manner to how we currently have ApiSession.getLiveContract or ApiSession.getLiveJson.

Ability to filter ApiSession events when subscribing

Current ApiSession execute method is using a getReceipt boolean flag which we would like to remove.

We think this flag is extra considering the returnType which can be: TypeOfExecutionReturn.Record, TypeOfExecutionReturn.Receipt or TypeOfExecutionReturn.Result.

If we do get a receipt, considering the returnType, we want to emit it if there are any listeners subscribed for TRANSACTION_ON_RECEIPT_EVENT_NAME event.

Considering the fact that there are multiple types of transactions which are done, we want to give user the ability to filter out some of this transactions if needed.

It would be great to have use a wrapper for the EventEmitter so we can filter some of these transactions out, based on transaction type and maybe also by the status on the receipt.

Invalidate LiveEntity ops following a self-deletion

Once a developer calls LiveEntity.deleteEntity(), all network operations following it should error out since, if deletion is successful, the entity won't be live anymore.

For reference, deleting LiveEntitys was added in #19

ContractRegistry - Support single-file, multi-contract entries

Currently ( following #32 ), generating a ContractRegistry from the following contracts:

a.sol
inner/b.sol

with a.sol containing contract A and b.sol containing contract B; contract C
yeilds

{
    "a": <contract A ABI>,
    "inner/b": <contract B ABI>
}

and contract C gets discarded because we only support one contract reference per ContractRegistry entry.

Ideally, we would like for ContractRegistry to reference all file-parsed contracts:

{
    "a#A": <contract A ABI>,
    "inner/b#B": <contract B ABI>,
    "inner/b#C": <contract C ABI>,
}

Under these circumstances, are we ok with the property naming?

Implement ContractRegistry for all ES environments

Currently, conditional export rules implemented by #22 and present in package.json expose ContractRegistry for all ES module runtimes.

This makes type: module node runtimes break.

We need to provide a solid ContractRegistry so that node environments can make use of while bundlers might dynamically generate contract-registry code.

Implement LiveAddress.equals(AccountId)

We already support LiveAddress.equals(string) and, of course, LiveAddress.equals(LiveAddress).

Might as well allow for AccountId comparisons.

This is already being used in our test-base and could simplify coding.

Refine `LiveFile` and `LiveJson` usage model

LiveFile (inherited by LiveJson) is exposing a getContents() method to retrieve the underlying content as a Promise<Uint8Array>.

We need to have:

  • add a parameter to getContents called update which is a boolean defaulting to false that, when set to true does a FileContentsQuery network action, updating the underlying content in the process. If it's false, it retrieves the stored data in Uint8Array format.
  • both LiveJson and LiveFile should use the query result to update it's internal data reference
  • Implement LiveJson.toString() which will stringify its data
  • Implement LiveFile.toString() which will return its internal data (if it's a string) or <binary File content> if the data is a Uint8Array.

toString() implementations will allow for fluent formatting in structures such as This is the file: ${liveFile}.

Refactor test/utils.ts to export an utility object

Currently, test/utils.ts is exporting individual functions such as:

  • read
  • load
  • ...

most of which have a relativeTo path argument that we the wrap in all different test-groups such as:

  • general
  • solidity-by-example

This adds unnecessary LOCs to the test definition files which can be avoided if we would work with a utility-object instance instead which would let us instantiate it per testing-module similar to: new TestingUtility(relativeTo: string) which we would then use normally via calls such as testingUtility.read(...).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.