Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
175 lines (116 sloc) 7.78 KB
description
This is a reference to the NEAR protocol blockchain. This teaches you what you need to create smart contracts on NEAR.

Writing Contracts

Contracts

What is a "contract?" It's the container for all the variables, functions and state of the blockchain portion of your application.

On NEAR, you just need to declare and export a function in TypeScript. Below is a fully functioning smart contract (see it running here):

// main.ts

export function hello(): string {
  return "Hello, World!";
}

You can also access the context in which the contract is being executed by using the contractContext object. This gives you access to variables like the sender or the contract's name via contractName.

See more about contractContext in autogenerated docs.

View and Change functions

There are two types of functions that can interact with the blockchain -- "view" functions and "change" functions.

  1. View functions do not actually change the state of the blockchain. Imagine a function which, for instance, just checks the balance of a particular account. Because no state is changed, these functions are lightweight and generally safe.
  2. Change functions modify state, for example by updating the balance someone holds in their account. You need to be careful with these functions so they typically require explicit user authorization and are treated somewhat differently.

Private and Public Functions

Methods with names prepended by an underscore _ are not callable from outside the contract. All others are available publicly in the client.

export function _myPrivateFunction(someInput: string): void {
  // Code here!
}

export function myPublicFunction(someInput: string): void {
  // Code here!
}

State

Like with web servers, function calls are stateless. Any state that you want to save to the blockchain needs to be explicitly saved by interacting with the storage object.

This object provides an interface to the blockchain storage. It is a standard key-value store where keys are strings and the values can be multiple types including string, bytes, u64. Anything else needs to be first converted into these types.

See the storage docs for the full reference.

You can also save data using persistent collections discussed below.

Collections

There are currently four types of collections. These all write and read from storage abstracting away a lot of what you might want to add to the storage object.

  • Vector
    • Acts like a persistent array
    • You can create a vector like this:
      • let vec = collections.vector<string>("v");
      • See the full implementation here
  • Map
    • Acts like maps you'd find in most languages
    • Yau can create a map like this:
      • let m = collections.map<string, string>("m");
      • You can use the map with m.set(key, value) and m.get(key)
      • See the full implementation here
  • Deque
    • Implementation of a deque (bidirectional queue).
    • You can create a deque like this:
      • let d = collections.deque<string>("d");
      • See the full implementation here
  • TopN
    • Used for creating ranked lists
    • You can create a TopN collection like this:
      • let t = collections.topN<string>("t");
      • See the full implementation here

The letter passed in as an argument (e.g. "v" in the case of the vector) is the key that gets assigned as a prefix to distinguish the collections from each other (precisely because they're persistent).

NOTE: if you're coming from JavaScript, you might not be familiar with the type declaration in the two brackets <>. In TypeScript, need to declare the types that any collection is going to take.

Arrays

Arrays are useful for storing multiple instances of state, sort of like a small database. Again, arrays here are just normal TypeScript arrays which act a lot like JavaScript arrays and have useful methods like push available.

// Creating a dynamic size array
let myArr = new Array<number>();

There is not currently syntactic sugar for array iterators like map.

Iteration

Iteration follows the standard TypeScript format:

// set i to a type u64
for (let i: u64 = startIndex; i < someValue; i++) {
  // do stuff
}

Classes

Classes are normal TypeScript classes and more information can be found in the TypeScript Handbook. We don't have structs, we have TypeScript classes instead.

You will generally want to define your classes in a different file and then import them:

// 1. define the class in the `assembly/model.ts` file
export class PostedMessage {
  sender: string;
  text: string;
}
// 2. Import the class to your `assembly/main.ts` file
import { PostedMessage } from "./model.near";

There are no structs.

Function Declarations and Return Values

Function declarations follow standard TypeScript conventions, including the parameters they take, optional arguments and return values. See the TypeScript Handbook for more info.

Random Numbers

Randomness is challenging in blockchains because multiple nodes have to execute the same code and come to a consensus on the same result -- so all code has to be deterministic. Thus one should always be cautious when employing randomness to realize that it can be predicted in advance to some degree.

In this case, randomness is calculated using the hash of the block's seed. This provides a suitably random number for any low-stakes calculations but should be avoided for high-stakes ones like lottery payouts.

// returns a random 32-bit integer
let myRandomNumber = near.random32();

See more about functions exposed in the near namespace in the Github docs.

Events

Sometimes you want your front end to automatically update if something changes on the back end. For example, if you have a messaging app that should update your screen when your friend sends you a message. Currently, you will need to poll the chain to make this happen.

In the future, we may expose event emitters and listeners as syntactic sugar. If this is important to you, reach out on Discord.

Math

Mathematical operations in TypeScript are done in the same way as JavaScript. See more in this article.

Time

Time is one of the most difficult concepts in blockchains. In a singe-server-based environment like web developers are used to, the server's (or database's) clock is ok to rely on for creating timestamps.

Because the blockchain's state is determined by a consensus among many nodes and must be deterministic and adversary-resistant, there is no way to settle on a "correct" clock time while code is being run.

You can pull timestamps from the client side (eg the JavaScript running on the user's computer) but that should come with all the usual warning about not trusting anything a client sends.

For less exact measures of time, the block index value is sufficient. This will look something like:

// Note: Not implemented yet...
contractContext.blockIndex();

Some solutions to the time issue include using "trusted oracles" but that's outside the scope of this doc.

You can’t perform that action at this time.