Gaps in NEAR development tooling

By popular demand, and as having made some attempts to develop on the current NEAR protocol, I will list some gaps in the tooling. If you compared NEAR development to other chains, some of these are taken granted and are if not must to have, on very high priority to have to build any large decentralised applications.

1. Smart contract frameworks for tokens

This is actively being worked on the progress has been awesome lately. Token frameworks will hopefully soon also cover metadata, burning, minting and such. We will also need base libraries for managing token balances with a smart contract, like a DEX, and this library should have well-defined best practices for managing cascading token transfer promises when interacting with other contracts. When decentralised applications grow more complex, another sore point will be interface registry and how to ask contracts if they support certain interfaces.

2. E2E testing framework

Currenly NEAR Rust smart contracts support unit and simulation tests. There is no ganache-like testrpc chain. It is difficult or impossible to use the current framework for example when developing frontends for the smart contract. Driving NEAR provided shared test chain to different states for e.g. for UI tests is slow and cumbersome.

NEAR should invest to its own Javascript (web3.js like) and Python (web3.py) like development frameworks that include testing suites.

From Hardhad tutorial we can find the example of level of easiness that must be achieved for high developer productivity:

The example is very simple and all the heaving lifting happens on the background, Developers do not need to care about spinning up the process, resetting blockchain or accounts between tests, and so on.

Waffle setup code is here - you can see all the stuff it offers as a standard development dependency for all projects. It delegates most of the code to other packages, so at the beginning of the each test it grabs a list of accounts that have prefilled balances by the node.

And behind the scenes Ganache sets up the blockchain for you. But Ganache is in-process EVM reimplementation so this is not such a good example for the NEAR to follow in the currebt state:

A better example is from web3.py where Python based tests can also spin up and down geth node similar to near up:

Then a good list of what features are needed for smart contract testing in generally can be seen in OpenZeppelin Test Helpers:

  • Check that transactions revert for the correct reason
  • Verify that events were emitted with the right values
  • Track balance changes elegantly
  • Handle very large numbers
  • Simulate the passing of time

Important is “passing time”: the test can explicitly tell when the node is allowed to mine the next block.

Also another good list what testing specific RPCs a node should implement can be copied from Ganache:

3. Smart contract ergonomics

Currently NEAR Rust smart contract framework needs some more life quality improvements for developers. Handling promises is clunky e.g. compared to Elrond - a blockchain with almost identical principles with NEAR.

Here is an example of how to do a token transfer promise and callback in Elrond.

Creating a transfer - erc20_address can be a in a different shard (I assume this, as I could not confirm this from Elrond core devs, only from third party devs.):

	fn distribute_prizes(&self, lottery_name: &BoxedBytes) {
		let info = self.get_lottery_info(&lottery_name);
               ....

		let erc20_address = self.get_erc20_contract_address();
		let erc20_proxy = contract_proxy!(self, &erc20_address, Erc20);
		erc20_proxy.transfer(&winner_address, prize, lottery_name);
	}

Receiving a transfer - how does a promise callback look like:

	#[callback]
	fn transfer_from_callback(
		&self,
		result: AsyncCallResult<()>,
		#[callback_arg] cb_sender: Address,
		#[callback_arg] cb_amount: BigUint,
	) {
		match result {
			AsyncCallResult::Ok(()) => {
				// transaction started before deadline, ended after -> refund
				if self.get_block_nonce() > self.get_deadline() {
					let erc20_address = self.get_erc20_contract_address();
					let erc20_proxy = contract_proxy!(self, &erc20_address, Erc20);

					erc20_proxy.transfer(&cb_sender, cb_amount);

					return;
				}

				let mut deposit = self.get_deposit(&cb_sender);
				let mut balance = self.get_mut_total_balance();
				deposit += &cb_amount;
				*balance += &cb_amount;

				self.set_deposit(&cb_sender, &deposit);
			},
			AsyncCallResult::Err(_) => {},
		}
	}

Rust SDK documentation needs polish - there are many Rust macros that have zero documentation and are only covered in tutorials. Tutorials and documentation should be all cross-linked - just building documentation links between different silos of documentation could be a task for junior developer.

(As a side note Elrond and NEAR use of Rust is so identical that there could be some toolchain parts that are ripe for co-operation, like creating crates and compiling Wasm. I do not see it impossible target that there can be one source for smart contract that compiles down to both Near WASM and Elrond WASM.)

4. Indexer and events

There needs to be an easy way for JavaScript frontends to read the smart contract state - the equivalent of TheGraph in Ethereum world. Currently, smart contracts do not even offer Event equivalents.

Currently there is no point doing any dApp on NEAR, as a develop you would need to figure out these things “hard way”. Also this ties to E2E testing: after you fire a transaction, how do you confirm your UI goes to the matching state after tx completes.

13 Likes

Thanks so much for this, truly. I was wondering what you’d think about a streamlined nearcore and local setup. As of right now, having a lightweight nearcore like ganache doesn’t seem to be in the cards. Do you think it would be beneficial to have a “heavyweight” Docker container with all the offerings? (Wallet, Explorer, node, etc.)

1 Like

I think what we need as v0 is just an easy way to run tests against local network. Like we already have most of moving parts, it’s relatively easy to run local network using nearup GitHub - near/nearup: Public scripts to launch NEAR Protocol betanet and testnet node

But you’d want it happen automatically when running integration tests with local environment vs having to manage it separately.