GEAR CONTRACTS GEAR NANO GEAR COMPUTER BLOG
Gear is general purpose computation engine that runs on top of bitcoin.
This means you can create an immortal piece of code whose state is 100% auditable.
The Gear SDK lets your write arbitrary programs, publish them to the blockchain,
and handle reads and writes to those files.
Although the sdk currently only supports C++,
it can be extended to handle Python, Go, Rust, C, and much more.
1. Bitcoin as the consensus engine, payment system, and write interface.
1. Web Assembly as the compilation target.
2. Planaria to scrape the blockchain and update contract state.
3. Planarium to store state to disk and serve over HTTP.
Ethereum and other smart contracting blockchains have failed to scale
or provide any tangible benefits over the bitcoin blockchain itself.
We are building a smart contract platform
the way it should have been built the first time. On top of bitcoin.
We want to take MetaNet to the next level
by turning it from a distributed filesystem
into a distributed operating system.
We are moving up the stack from simple hard drive storage
to actual actual cpu/memory computation.
All running natively on bitcoin, ... sv.
Compile, test, and deploy contracts to bitcoin.
GEAR CONTRACTS
npm i gear-contracts -g
1. Choose your project configs. Saves to a local package.json file.
2. Choose contracts you want to start working with.
3. Creates .cpp and .h files for the chosen contracts.
1. Generates a bitcoin keypair [privateKey, publicKey, address] to keys.json file.
2. Saves qr code of address to address.png file.
Compiles the contract files into a web assembly binary
[contractName].out.wasm file, and the Emscripten embind javascript interface
[contractName].out.js file
Files are written to ./output directory.
Calls the test file for the contract in ./tests
Uses the tape testing framework which comes bundled with the global install.
MAKE SURE YOUR KEY IS FUNDED BEFORE PROCEEDING.
Contract packages are around 30 kb. 10 cents should be enough.
1. Creates a tempory ./tmp directory to hold contract package.
2. Moves .h, .cpp, .json, and .js files into the temporary folder
3. Compresses package into a gziped tarball [contractName].tar.gz
5. Asks for constructor inputs if applicable.
6. Formats op_return transaction with [gear, contract.tar.gz, constructor].
7. Broadcasts transaction to the bitcoin chain. Returns transaction hash
THE TRANSACTION HASH IS NOW ALS0 YOUR NEW CONTRACT ID
GEAR NANO
npm i gear-nano -g
npm i pm2 -g
gear-nano init 6787dfa742f963c6641e901d8e81da2930d62820b7837b7fd1e28c7bbf394727
1. Fetches contract package tar ball from the on chain transaction. `contractID` is the transaction hash of the contract deployment.
2. Fetches the `blockHeight` from the transaction.
3. Fetches the `constructor` input from the transaction.
1. Converts emscripten module [contractName].out.js and wasm bytecode file [contractName].out.wasm into a single javascript Module.
2. Initializes contract with the constructor input from deployement.
3. Starts Bitbus and Neon Planaria scraping servers which filter for contract calls pointed at the contractID.
4. Initializes contract inside the WASM virtual machine runtime.
5. Starts block handler that aggregates contract calls and feeds into the contract.
1. Starts Planarium server which accepts state updates from the processor over ZeroMQ.
2. Starts Http server which allows you to query the state at a given block height.
1. Starts Planarium server which accepts state updates from the processor over ZeroMQ.
2. Starts Http server which allows you to query a transaction by the transaction hash.
1. Clears the server state by deleting `StateDB`, `TxDB` and `tape.txt`.
The "contract" is just a pure c++ class, as easy as that. The only difference are special key words input parameters that can use information verified by the chain.
SENDER
The bitcoin address verified in script by the on chain transaction.
BLOCK_HEIGHT
The height of the block in which the transaction was processed.
BLOCK_TIMESTAMP
The timestamp of the block in which the transaction was processed.
Just as you normally do with c++ code,
this is where you define the interface to your program.
This will include the class instantiation
along with the class level variables and functions.
#include <string>
#include <map>
class FungibleToken {
public:
unsigned int supply;
std::string owner;
std::map<std::string, unsigned int> balances;
FungibleToken(std::string owner);
const std::string& setOwner(std::string SENDER, std::string newOwner);
const std::string& mint(std::string SENDER, unsigned int amount);
const std::string& transfer(std::string SENDER, std::string recipient, unsigned int amount);
const unsigned int& getSupply();
const std::string& getOwner();
const unsigned int& getBalance(std::string address);
const std::map<std::string, unsigned int>& getBalances();
};
This is where you put the implementation of the different functions.
These functions can modify the state variables which will be queryable via gear-nano.
Currently the framework only provides support for c++11 and the std library.
Emscripten's embind pattern is used to export a javascript class
that maps one to one with the underlying c++ class.
This allows for a seamless bridge between planaria and your contract.
EMSCRIPTEN_BINDINGS(FungibleToken_example) {
register_vector<string>("keys");
register_map<string, unsigned int>("balances");
class_<FungibleToken>("FungibleToken").constructor<string>()
.function("setOwner", &FungibleToken::setOwner)
.function("mint", &FungibleToken::mint)
.function("transfer", &FungibleToken::transfer)
.function("getSupply", &FungibleToken::getSupply)
.function("getOwner", &FungibleToken::getOwner)
.function("getBalance", &FungibleToken::getBalance)
.function("getBalances", &FungibleToken::getBalances);
}
Until we get our act together and engineer a js based c++ parser,
you will have to manually create the abi as a json [contractName].json file.
{
"constructor": {
"owner": "string"
},
"setters": {
"setOwner": {
"SENDER": "string",
"newOwner": "string"
},
"mint": {
"SENDER": "string",
"amount": "int"
},
"transfer": {
"SENDER": "string",
"recipient": "string",
"amount": "int"
}
},
"getters": {
"getSupply": {
"returns": "int"
},
"getOwner": {
"returns": "string"
},
"getBalances": {
"returns": "map"
}
}
}
FungibleToken::FungibleToken(string owner) {
this->supply = 0;
this->owner = owner;
}
const string& FungibleToken::setOwner(string SENDER, string newOwner) {
// check that SENDER is the current owner
if (SENDER != this->owner) {
return "fail";
}
this->owner = newOwner;
return "pass";
}
const string& FungibleToken::mint(string SENDER, unsigned int amount) {
// only the owner can mint
if (SENDER != this->owner) {
return "fail";
}
// mint tokens, assign to owner
this->supply = this->supply + amount;
// increment owner balance
if (this->balances.find(SENDER) == this->balances.end()) {
this->balances.insert(pair<string, unsigned int>(SENDER, amount));
} else {
unsigned int balance = this->balances[SENDER];
this->balances[SENDER] = balance + amount;
}
return "pass";
}
const string& FungibleToken::transfer(string SENDER, string recipient, unsigned int amount) {
// check if SENDER has sufficient funds
if (this->balances[SENDER] < amount) {
return "fail";
}
// increment recipient balance
if (this->balances.find(recipient) == this->balances.end()) {
this->balances.insert(pair<string, unsigned int>(recipient, amount));
} else {
unsigned int recipientBalance = this->balances[recipient];
this->balances[recipient] = recipientBalance + amount;
}
// decrement SENDER balance
int senderBalance = this->balances[SENDER];
this->balances[SENDER] = senderBalance - amount;
return "pass";
}
const unsigned int& FungibleToken::getSupply() {
return this->supply;
}
const string& FungibleToken::getOwner() {
return this->owner;
}
const unsigned int& FungibleToken::getBalance(string address) {
return this->balances[address];
}
const map<string, unsigned int>& FungibleToken::getBalances() {
return this->balances;
}