This functionality is only available on dev-net
This functionality is in development
The target audience for this section is a developer with some previous idea of
web3
programming, and therefore, at least experienced enough to set up a
javascript (typescript) nodejs environment where to run blockchain related
tooling.
In addition to some idea of standard EVM web3
programming, you might need a
short crash course in addition to the information on this page.
Smart contracts tooling & Development experience.
The cweb-tool
for smart contracts is a Typescript nodejs script to manage
smart contract code sharing and contract deployment for developers.
cweb-tool
does not require privileged access to a
Coinweb node, but it does
require non-privileged access to a wallet-service
node (which is an API
provided by a Coinweb node)
to query the state of the network.
Lazy smart contract deployments
Deployments of contract modules is lazy by default. That is, you can develop, test, and have dependencies on contract modules that have not yet been deployed to Coinweb.
Access to CWEB funds is required to deploy smart contracts to blockchain. However, if access to CWEB funds is not available, it is instead possible to create deployment artifacts that can be deployed by third parties independent of the developer.
If neither CWEB funds nor a third party is available, the contract modules can be published and whoever will use them as a dependency will end up deploying them.
The separation of deployment artifacts from actual deployments makes deployment lazy in Coinweb. Whoever finally deploys will fund dependencies that are not yet deployed.
When deploying your smart contracts using the cweb-tool publish
command, you
might experience that all actions are filtered out and nothing is deployed
on-chain. This is usually because the smart contract components (the actions)
have already been deployed.
Coinweb dApp development.
Coinweb dApp development is structured around the idea of contract-modules.
Every contract-module is a normal typescript (and hence javascript) package,
and can be published or imported as such, but not every typescript package is a
coinweb contract-module package. A contract-module can import code from
other "contract-module" packages, but currently, it won't be allowed to import
code from non-contract-module packages with the exception of the
@coinweb/contract-kit
package. The reason for this limitation is purely
implementation related (currently the lock
files are not handled correctly, we
expect to lift this limitation soon).
Each contract-module has 2 parts:
-
on-chain logic: This logic will be packed and deployed as an on-chain contract template, that is, a type/kind/family/factory for on-chain smart contracts. Following this template, it will be possible to call specific instances; for example, a contract template could be a generic NFT contract describing a specific nft-standard, and an instance of it will be a specific NFT contract (i.e bored panda) following that specific standard. As its name indicates, this will be stored on-chain, so it has to be small in size (i.e not including image assets), otherwise it will be too costly to register.
-
off-chain logic: This is an arbitrary javascript package (and hence can include any kind of file, such json, images, css, doc annotation, TS types) which is cryptographically linked to the on-chain logic so there's a 1-to-1 relation between them. Even though this is a normal package that can be distributed as a normal package and it is not stored on blockchain, the requirement of being 1-to-1 implies that this package is immutable, only a single version is possible; if it is modified, even if it is just adding a whitespace or adding an invisible asset file, its link to the original contract-module will be broken, and it will be considered part of a different contract-module.
The on-chain logic and the off-chain logic parts belonging to the same contract-module are linked in the following way:
-
The contract-template-id (hash) and the contract-module-id (hash) are the same.
-
The
off_chain_logic.ref
file is a hash of every packaged file with the exception of theindex.js
file.- The
index.js
file is auto-generated, and consists of 4 or 5 simple lines reporting everything and defining the constants:const CONTRACT_TEMPLATE = «contract-template-id»
const OFF_CHAIN_LOGIC_ID = «off_chain_logic.ref»
const INTERPRETER_ID = «...»`
- The
The reason to autogenerate this file is to avoid cycles for the hash generation
-
The merkleized VFS (
ContractTree
, see self-registration) of the contract template includes a file containingoff_chain_logic.ref
.-
Hence the contract-template-id (the hash of its
ContractTree
), which is also the contract-module-id, covers theoff_chain_logic.ref
(hash). -
Because the
ContractTree
of a smart contract instance is a superset of theContractTree
of the template it follows, it means that the contract-id of contracts created after this template will also be linked to this same off-chain-logic (in this case it will be an N-to-1 relation, as many instances will be linked to the same off-chain logic).
-
We speak about contracts (templates and/or instances) getting registered rather than initiated, because, by definition, in Coinweb, every possible smart contract already exists and can be called since the genesis block. "Registering", rather than creating them, is to store some claims about how to access the contract, following a specific convention, in such a way that it is easier, cheaper and more convenient to call them for the rest of the ecosystem
See self-registration of smart contracts for more information.
This functionality is in development
In the current tooling setup, everything is currently a contract-module. This includes libraries that are 100% off-chain, meaning they will always have an onchain contract-template, even if it is trivial (i.e a family of contracts that always trigger an exception no matter what). The reason is that this consistency simplifies the tooling; also, even though it might seem wasteful to have useless contracts, right now, under the hood, it will only use 2 claims (one for the code itself, and one for an index link to it), so it doesn't add any extra space. In the same way, there might be contract-modules with trivial on-chain logic, and there might also be some contract-modules with trivial off-chain logic; but in any case, trivial or not, they will always contain both parts.
Naming and dependencies:
Any contract-module use its contract-module-id
as its package name starting
with cweb_
to make it syntactically valid as name (for example, the name of a
package could be
"cweb_6df2b349518e2ec0397d896f50efffb83fd32805baee00f75063e2292fe4cb7b"
). This
has some implication:
-
It makes the
yarn.lock
file redundant for thecweb-tool
. -
It fixes dependencies, so given a
contract-module-id, the behavior of the callee module does not depend on the dependencies of the caller module, meaning we can guarantee that the code executed by a function from a specific
contract-module-id` is always the same.- This is the main reason we only allow dependencies to other
"contract-modules" and not to arbitrary js packages, as this invariant would
get broken. It might be possible to solve this using the info from
yarn.lock
and code preprocessing, but this is out of the scope of this iteration of the smart contract ecosystem.
- This is the main reason we only allow dependencies to other
"contract-modules" and not to arbitrary js packages, as this invariant would
get broken. It might be possible to solve this using the info from
Set-up:
A contract-module is created, as usual, by creating a package.json
file. Any
field with the exception of contract-module-alias
is allowed. As a dependency,
any contract-module package or the @coinweb/contract-kit
is allowed. The
special field interpreter_id
will be a hash identifying the WASM interpreter
(i.e the wasmquickjs
version) and its configuration (the env-var and cli-args
passed to the interpreter binary). It is important to pick the right
interpreter_id
as the API available does change from interpreter to
interpreter; the simplest approach is to copy&paste the interpreter_id
value
recommended by the @coinweb/contract-kit
documentation.
In a future version, the interpreter_id
might be automatically selected based
on the @coinweb/contract-kit
version.
Though there are limitations on what dependencies are allowed, there are no
dev-dependency restrictions, i.e. tsc
or jest
can be used.
You are free to use any vanilla javascript or typescript approach to writing code, and configure that for your project. You can also use other tools such as Babel or Webpack.
For the first iteration of the tooling, only a single file will be accepted for on-chain logic, so Webpack or similar is strongly recommended.
As contract-module
have no human-friendly name in the npm system, the
developer will make use of one of the "known-contract-template" indexes, these
are big tables linking contract-module
names (such
"cweb_6df2b349518e2ec0397d896f50efffb83fd32805baee00f75063e2292fe4cb7b"
) to
their module alias names (such "token_balance_keeper") and providing extra info
such the package repo url, package registry and documentation. Within
package.json
, it is possible (and recommended) to rename those
"contract-modules" to their human alias, so within the code, only human-readable
package names are used, and it is easy to upgrade dependencies if required for a
new version. Anyone can create their own "known-contract-template" index, and
the developer can chose the index from anyone (or even create his own).
Though the content of the index is verified so an index can not "directly" lie, the "human alias" is not unique, and a malicious index curator might purposely create contract-module with an already commonly used alias, to mislead a developer into injecting malicious code! For that reason, on https://coinweb.io , a whitelisted "known-contract-template" index will be suggested.
Integration with the subresource integrity system used by yarn
and npm
is
expected in future versions of cweb-tool
The package-lock.json
or yarn.lock
file will be generated and though it will
be redundant for the contract-module dependencies, it will still be required for
the dev-dependencies.
package.json
and tsconfig.json
conventions.
cweb-tool
requires the project to follow some standard conventions to work
properly, namely:
- Generated code and assets to be published should go under
lib/
. - Main entry point should go under
./lib/main.js
- The file
./lib/index.js
should not be created. - Main
"types"
field should be defined in./lib/index.d.ts
. - The file
./lib/main.ts
should not be created. node_modules
should be flattened.onchain.js
(oronchain.ts
) shall "webpacked" into a single file under./onchain_lib/main.js
. (This is a provisional requirement to be lifted).
All but the last one requirement are standard conventions followed by default by most projects and tools.
The developer will not implement index.ts
, but will instead implement the
package as having 2 parallel entry points, onchain.ts
and offchain.ts
,
fulfilling an expected interface (i.e cweb_main
).
Do not pay too much attention to the details of this section, as it will most probably heavily change once we start gathering experience data from actual usage of the js ecosystem and CWEB tooling together.
Installing
- npm
- Yarn
- pnpm
npm install @coinweb/cweb-tool
yarn add @coinweb/cweb-tool
pnpm add @coinweb/cweb-tool
Ensure that cweb-tool audit
is run after any package installation:
{
"scripts": {
"postinstall": "cweb-tool audit"
}
}
The audit checks:
- For all dependencies from
package.json
installed intonode_modules
:- That they are flattened.
- That they are valid
contract-modules
:- That they only depend on other
contract-modules
and that those are also part of the parentnode_modules
folder. - Renaming the package name to its "contract-module-alias"
package.json
field, then removing "contract-module-alias"package.json
field and removingindex.js
file, then, processing the package again (cweb-tool pack
) produces the same package as before.
- That they only depend on other
Publishing, registry & deployment:
There are 3 steps to publishing "contract-modules" :
-
A) Make the package content available on some public package registry (such
npm
or some gitlab-hosted public registry). -
B) Share your package with the coinweb community by adding an entry for your contract-module in some or several "known-contract-template" indexes. Specifically, the official
https://coinweb.io/known-contract-template.yaml
index is relevant. -
C) Make the on-chain logic from your contract-module easily accessible from other dApps and wallets by on-chain registering the contract-template and all its dependencies. Or if you are focusing on some specific instance, registering that specific instance.
A: Publish to some package registry:
Of all the steps, the first is the most important one.
-
Build the project: that is, execute
tsc
,babel
,webpack
or any other tool required in order to get the desired files under thelib/
folder. -
Transform the package into a contract-module package: execute
npx cweb-tool pack
to transform a normal idiomatic package into a contract-module package. -
Publish the contract-module package as a normal package: execute
yarn publish --folder «contract-module-folder»
.
B: Share the contract-module package through some "known-contract-template" index:
Once the package is published in a registry, we can add it to an index; because most of the package content including its metadata is hashed, and the hash is the name of the package, anyone can add a package entry to a "known-contract-template" index using either the original package registry or any mirror.
To add a package to a "known-contract-template" index, the developer will need
to make a request for the new entry to the index maintainer; since all the info
the maintainer needs for the new entry is already in package.json
, the
requester only needs to provide the maintainer with the url of the package. This
request could be done automatically (i.e an http call to some endpoint) or
manually (sending an email to the maintainer asking him to add his project), of
course, the second option is easier to implement :-) .
Including a contract-module in an index implies some sort of trust from the
maintainer to the requester, because a contract-module could use a misleading
contract-module-alias
to lure readers of the indexes into a phishing attack.
To avoid that issue, the index maintainer could require some sort of
authentication from the requester or could require not to push already used
alias, or even check whether the package looks malicious or not. Before
accepting the request, the maintainer should check that the package is a valid
contract-module and that the registry is open, in order to do that, he could:
-
Create a mock contract-module importing the requested contract module.
-
run
yarn install
(it will check that the code can be downloaded from the registry). -
run
npx cweb-tool audit --folder node_modules
(it will check that the package is an actual valid contract-module).
In addition to that, there are other things some maintainers could (should?) check, such as:
- it uses compatible software licenses.
- its alias doesn't conflict with other known modules.
- the requester is not a spammer.
- the metadata from package.json is valid, such that:
- the link to the source code repo (not to be confused with the package registry) exists and relates to the package.
- the package maintainer's email exists and relates.
- the link to the docs exists
- ...etc
- the requester is not a spammer
- ...etc
All or some of these checks could be done automatically, but for the first version, the whole process could be done manually.
C: Onchain registering:
To be shared and used by other developers, your code doesn't need to be
registered or uploaded to blockchain; this is an important point since uploading
code to blockchain will cost CWEBs (on the other hand, requiring some CWEB to
upload code to blockchain could be a good anti-spam feature). Once your code is
on a "known-contract-template" index, anyone with access to that index can
upload/register your code on blockchain; and actually, if requested to register
some contract-module, the cweb-tool
will automatically upload all its
contract-module dependencies, meaning that, if you implement A
and someone
else implements B
that depends on A
, chances are that the implementor ofB
will upload A
. An alternative option, the index maintainer could be the one
actually uploading the code related to its index.
To upload code to the blockchain, the uploader shall execute:
WALLET_PRIV_KEY='xxxxxxxx' npx cweb-tool publish --index «url to index that includes this contract-module» --broadcaster ../broadcaster_conf.json
Note that:
-
This will cost CWEB, and hence needs access to some private keys.
-
This will connect to the network (to a wallet-service through a broadcaster) to submit the uploading transaction, but also to request the state of the network, so it can detect which files need to be uploaded. As a simplification, it assumes that all your dependencies are in the index. As another simplification, it assumes all the entries of the index are dependencies of yours (so, remove unnecessary index entries!)
-
Whether something has been uploaded or not depends on which network the broadcaster is connected to, for example, it might have been deployed on stagenet or dev-net (i.e ganache blockchains), but not on betanet.
-
Uploading code can fail midway, there can be race conditions, and most probably reorg issues could produce misses. All of these mean that a file or a contract could be uploaded/registered more than once in rare cases; this won't be an error or a problem but will result in unnecessary extra cost for the uploader.
Under the hood, the publish
command is a set of different, smaller and more
atomic commands:
-
gather-actions
: reads index files, interpreter files and/or package registries code to produce a representation of what actions will be required to get executed. In this representation, an action will be a tuple of a transaction to execute + the key of the claim expected to be created after the transaction got executed. -
filter-actions
: reads the state of the blockchain to remove unnecessary actions (already created). Just remove those actions whose key already exists. -
execute-actions
: having access to CWEB funds and a broadcaster, execute the transactions associated with a list of actions. This is just acli
facade to the current implemented Coinweb tool.
Testing:
Dockerised versions of dev-net 0.1 will be made available for local development.
The below description is not yet available for external developers.
Steps to test:
-
Deploy (locally?) your testnet Coinweb network, including:
- truffle mocked blockchains
- Coinweb-node (parser, l2-computer, shufflers)
- explorer backend + wallet-service. (conceptually those 2 are the same)
- explorer frontend webpage
- broadcaster + l1-writer (to truffled blockchains) + broadcaster-wallet (i.e complete broadcasting service).
- some testing funds under user account (maybe we could have a default account for tester, like the one related to priv-key 1111111111111111111)
- (ideally) your phone's wallet-app should be able to connect to this network.
-
create your own
known-contract-templates.yaml
index:- including your package.
- including your package dependencies.
- including dApp instances you rely on (i.e LinkMint)
-
use
npx cweb-tool publish
over this test network.
nodejs and quickjs have different APIs! So even if it works when executed with nodejs, once executed with quickjs by the cweb-virtual-machine, it might fail. Fortunately, wasmquickjs (wasmedge's wrapping of quickjs), emulates nodejs APIs from quickjs, yet, this emulation might not be perfect.
Files involved:
cweb_network_conf.yaml
cweb_network_conf.yaml
: A configuration file containing connection information for the Coinweb network, including broadcasters and wallet-service. Internally, to execute some commands,cweb-tool
will need to open awallet
onwallet-lib
, for which it will need to pass some conf values, those will be the ones from this file (with the exception of the private key, which should not be on an insecure config file).
"known contract templates" yml index:
This yaml represents a list of "contract-modules" indexed by their alias. It is intended to be used and read by both human developers looking for the name/version of their project contract-module dependencies; and by the cweb-tool, to automatically deploy a set contract-templates, contract instances, interpreters and other files.
It also includes the list of wasm "interpreters" the developer can choose to configure his contract with.
Example of how it could look like:
# which "quickjs" versions that are avaliable to use.
interpreters:
# This is the `interpreter_id` the developers shall copy&paste on their `package.json`
422e37bab5f47a03092bdb5a19fe0b80522d83c901343db00046819bb97242ef:
version_date: 2023-08-17T11:58:52-03:00
alias: 'wasm_quickjs v12.3.4' # WARNING, this alias is not verified.
entry_point:
url: 'https://fake-url-to-wasmedge.com/files/quickjs.v12.3.4.wasm'
blake3: 6b704a3a9ae9e5ebde410127041bf5d03e82b5ba5273a6020118c2f4b2a1ddfc
auto_registry_code:
url: 'https://coinweb.io/files/autoregistry.js'
blake3: 957131fdf415ae5e35a5a80e4eb652bcd56b7f354ef7a505627cb46c071937c5
cli_args: '--execute "cweb_exec()" --out output/file.json --folder ./'
env: []
# Contract templates
templates:
token_balance_keeper:
# when this version was published
version_date: 2023-08-17T11:58:52-03:00
# The contract-template-id, require to define new instances of new `token_balance_keeper`.
contract_module: e48afe8b5234bb527ee4807f714d42901c77002ca1bb7e8e4e876fdd1626339f
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
# Some `token_balance_keeper` instances, that is, the `contract-template` + the `parameters`.
#
target_instances:
# instance contract-id:
#
2c35bc9dc83b798cc8dfb281dc30d787583b4af0119c66f865fec0d8124b207a:
# instance `parameter.json`
admin:
auth: 471e2a211bbe8d2e10c9ee7ae12a48c1df70980a9812bb96e68be01ca2c3fa04
account: null
67c3179410c8adae799d677dc0e6ed9a064538cc638fc6bf4b3ba5769a4b0e63:
admin:
auth: 471e2a211bbe8d2e10c9ee7ae12a48c1df70980a9812bb96e68be01ca2c3fa04
account: null
8a0581842b45e9783860ac988183e91ff64b85b1a443ca03beea68a15c0f88d4:
admin:
auth: 471e2a211bbe8d2e10c9ee7ae12a48c1df70980a9812bb96e68be01ca2c3fa04
account: null
limited_nft_changes:
version_date: 2023-08-17T11:58:52-03:00
# The `contract_module` is not only the contract-id of the template, but also the
# name of the `npm` typescript package containing this dApp (onchain contract code
# + offhcain code + types)
#
# These dApp package's code will be enriched with info such the contract hash-id.
#
# Packages names are hashes, but they are downloaded and installed using normal javascript
# tooling such `yarn` or `npm`. For example
# `yarn install 'cweb_e48afe8b5234bb527ee4807f714d42901c77002ca1bb7e8e4e876fdd1626339f'`
#
# We'll have a tool that will take as input a `node_modules` and for each dApp package will output:
#
# * whether they were correctly generated or not.
#
# * whether the contract-template is already registered or not.
#
#
# To prove that the off-chain code relates to the onchain code, the contract tree will include a
# hash reference to the off-chain code; because of some technical reasons, this hash and
# the module's hash are not the same (but are related).
#
# It is possible to prove that a contract-template relates to a dApp module **even if
# the contract-template has not been registered**.
#
# the npm package repository from where to install the dApp module
#
contract_module: 63a605980bb93ae2c5210c87f6a7a936f8990327b93f42dfaf67ddf62e55d1c8
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
Limited_minter:
version_date: 2023-08-17T11:58:52-03:00
contract_module: f44a9ca52dd323355f21840c9d79ad4a0432d2dbfc42830d16331e500ae22caf
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
bridge_curator:
version_date: 2023-08-17T11:58:52-03:00
contract_module: a3be81008b5095edd78a0472c2357d71e0d535af84d3d0e677e4d21d11f55c00
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
bridge_base:
version_date: 2023-08-17T11:58:52-03:00
contract_module: a5ffe1c440e2209387125ea1524b16c9a5a604c86afa93fad0132cd4ae4113d1
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
token_data_keeper:
version_date: 2023-08-17T11:58:52-03:00
contract_module: 93fd81ee8ccc24b228a59aa2e166d1d99deda991d36294ded6ae70f07581d7bb
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
onchain_game_example:
version_date: 2023-08-17T11:58:52-03:00
contract_module: bf68e0be6d457ba7102d2ed287097033945cfa75f9d538af4c61087bcd7d6cf2
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
restriction_node:
version_date: 2023-08-17T11:58:52-03:00
contract_module: cbdfcbbee9a490aca2a2bc6b859967836bfe3d1f00c72919711e1b12c0368f9d
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
ecdsa_contract:
version_date: 2023-08-17T11:58:52-03:00
contract_module: d60346116fde8ea71194a6e738cad43fe86d69ea6fff0e5903135128b8086843
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
bonding_curve:
version_date: 2023-08-17T11:58:52-03:00
contract_module: 581a9cf6e425520224de93b6ae14ca338a89b3f44a6569ff84c3d4549c2835d2
target_instances: []
package_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
auction_place:
version_date: 2023-08-17T11:58:52-03:00
contract_module: b5ed80a70587306ce541483d105ec015411cd4c2395473ff365a5077636e08a3
target_instances: []
pkg_mirror:
url: https://gitlab.com/package_registry/experimental/dapp-repository/
commit: 47c81fe47bfbb69e05c6782c2d91ab63aa10a678975a64682ec005f62731fd50
Notes:
-
The index, the
version_date
field is not verified and could be made up by the index maintainer (QUESTION: maybe it should be removed?). It is left there for convenience for CI/CD execution. -
The field
target_instances
is arbitrary, we could check (but on the first version it won't) that each target_instance id, is the right one, and that they are made following the template they are supposed to have; but it only indicates the instances the index maintainer wants to register, and hence it is completely up to the index-maintainer to decide what should be there. -
Some index maintainers might decide to add some "
description
" fields here and there or comments; but if so, these will be ignored by the tooling and not verified. -
This file should not be checked into source-code repos.(git).
-
This file is supposed to be stored in some package registry or web-accessible place (for example S3).
-
pkg_mirror
is not the url to the source-code repo, but the url to the package registry; this means it contains the code/files after they have been processed; but they do include thepackage.json
, which points to the source-code repo and documentation. However, for javascript, the files found in the package registry, and those on source-code repo are very very similar (unless something likeuglifyjs
had been used). -
the
auto_registry_code
is the js code used to "self-register" the interpreter, and it will affect the claim-issuer id under which we will be able to find all the files to execute it ... but it won't be part of the interpreter itself.
"Action list" yaml.
A list of "actions" to do if some claims don't exist, it is used internally by the tooling and it is not supposed to be read by humans. It is used by the different commands involved in deploying contracts. If the high-level commands are used, this file will not even be stored on disk.
Format:
# action 1
- key:
- «first key»
- «second key»
issuer: «issuer of the claim we'll lookup»
command: |
«a UI-command to be executed, using the same format as the QRs the wallet-app uses»
# action 2
- key:
- «first key»
- «second key»
issuer: «issuer of the claim we'll lookup»
command: |
«a UI-command to be executed, using the same format as the QRs the wallet-app uses»
Notes:
-
This should not be stored anywhere nor checked into a repo.
-
This same file could also be used to automize test deployment (i.e, initial state for some dApps).
"Target instances" yaml.
Represents the contract instances you want to deploy, especially useful while
testing locally or on stage-net; for example, it could be used to declare that
you want a "stablecoin" instance of a token contract to always be registered. It
is used by cweb-tool
to create the target_instance
section of the
"known-contract-templates" yaml.
The target interpreters will also be specified here.
Format:
target_contracts:
# contract 1
- template: «alias of template, such as"token_balance_keeper"»
parameters:
«an object representing the expected `parameters.json` the contract expects»
# contract 2
- template: «alias»
parameters: «parameters»
..
# contract N
- template: «alias of templa, such "token_balance_keeper"»
parameters:
«an object representing the expected `parameters.json` the contract expects»
target_interpreters:
«alias 1»:
entry_point: «url to the wasm file of the entrypoint»
cli_args: «the command line arguments the entry_point binary will be executed with»
auto_registry: «url to the registry js file»
env: # a list of env-variables the the entry_point binary will be executed with
- FOO: XOO
- RRR: EEE
«alias 2»: ...
«alias 3»: ...
contract_modules:
- «url or path to a contract module on a package registry»
- «url or path to a contract module on a package registry»
- «url or path to a contract module on a package registry»
- «url or path to a contract module on a package registry»
- «url or path to a contract module on a package registry»
Notes:
-
Hashes are not specified in this file, because this file is supposed to be written by a human, not a tool.
-
To freeze this file into a "known contract templates" file, we use:
$ npx create-index --target target_instance.yml -output known_contract_template.yaml
This will compute hashes.
- This file should be checked in a source-code repo (for us, on our cweb-dapps gitlab repo).
Commands
-
pack
: transform an idiomatic javascript package into a contract-module package; in order to do that it checks the contract-module id, it rename the package to it, and it generates theindex.js
file. -
audit
: it checks that a set of "contract-modules" from anode_modules
folder and/or from an index file are correct. In order to do that, it checks a few of simple restrictions (node_module flatten, all dependencies are on node_module ...etc); it checks that for each of those "contract-modules", runningnpx cweb-modules pack
doesn't change them (meaning they were "packed" using the tool), and if they come from an index, they check the alias from thepackage.json
and from the index file is the same. -
create-index
: transform a "target" file, into an "index" file. For that, it will need to compute hashes, and for that, it will need to download ("wget") files and install packages (yarn install
). NOTE: A first implementation could install packages and then remove them, this might be wasteful, but should make the implementation more robust and simple. -
publish
: it is actually the combination of 3 "smaller" commands: -
gather-actions
: transforms an index file (list of known template contracts and interpreters) into an action file. NOTE: it will not download files, it will try to get the packages fromnode_modules
, so if they have not been installed yet it will fail. -
filter-actions
: transforms an action file, into a (hopefully) smaller action file, by connecting to the coinweb network and checking which actions that are no longer required. -
execute-actions
: it will connect to a broadcaster to issue those actions as transactions. We'll have a flag to just emulate them or just to ask how much it will cost.
Implementation:
pack
Transforms the package into a contract-module package: execute
npx cweb-tool pack
will transform a normal idiomatic package into a
contract-module package:
- it will copy the original name of the package under the
"contract-module-alias" field on
package.json
, and remove the package name field. - it will remove (if exists)lib/index.js
andlib/index.d.ts
files. - it will hash all the files to be published (i.e
lib/**
andpackage.json
) to define theoff-chain-logic-id
hash. - it will look up what are the files (entry_point.wasm
,env_var.json
,cli_args
...etc) registered on chain under the{key: "registry", content: «INTERPRETER_ID»}
. - combining these interpreter files, with the
./onchain_lib/main.js
file as the contract-template's "onchain.js
" file, and theoff-chain-logic-id
as the contract-templateoff_chain_logic.ref
file; create the contract-template'sContractTree
. - hash theContractTree
to find out what would be the contract-template's id; and rename the package to this id (prepended bycweb_
). - create
lib/index.js
andlib/index.d.ts
:- they should rexport everything from
lib/onchain.js
andlib/off-chain.js
(and their.d.ts
version). - they should define the const hash ids used (
CONTRACT_TEMPLATE
,OFF_LOGIC_ID
andINTERPRETER_ID
).
- they should rexport everything from
Ideally (but maybe not for the first version), all this processing:
- will not be under the project folder itself but under some
target
folder. - it will copy files as symlink, to avoid duplicating them, and will not process/copy folder recursively.
- it will take into consideration file modification time to avoid unnecessary work.
publish
-
filter-actions
: it just needs to connect to some specific network (that also means some specific genesis-state) and check if some claims exist or not. It should connect through thewallet-lib
(and in future versions also connect to the l1-networks) so the result of these checks can be proved. -
gather-actions
: how it specifies:- a contract template: we should execute a
"self-registry" command to the
contract ref:
let ref = contract_ref(
[«interpreter-id»],
{
'onchain.js': «the package/onchain_lib/main.js file»,
'off-chain.ref': «the computed off-chain-id hash»,
}
) - a contract instance:
let ref = contract_ref(
[«contract-template-id»],
{ 'parameters.json': «the parameters field» }
) - an interpreter:
let ref = contract_ref(
[], // empty! defining from scratch!!
{
'entry_point.wasm': «...»,
'onchain.js': «the self registry script»,
}
)
With those "
ref
", we can defineContractRefV0
, and with thoseCallOp
to the "self-registry" method that all contracts and templates implement by convention; executing that transaction should get the contract or template registered, and the interpreter's files uploaded. The claim key associated for each of those actions would be:claim_issuer: «the template-id or contract-id»
first_key: 'self_registry'
second_key: ''For the interpreter, we'll register them as if they were a contract template (but without
off-chain.ref
) and compute its id the same way we would do for a contract instance or contract template (i.e, resolving itsContractTree
and hashing it).About how smart contracts do self-registration check here.
Some smart contracts rely on the
HashDataContract
to already have been registered in order to be able to self-register, so we might need to deploy this contract as if it were an interpreter. - a contract template: we should execute a
"self-registry" command to the
contract ref:
execute-actions
: A first version could just simply call the online development
tools we already have. Because deploying twice the same file is not a big issue,
this could just follow a "fire and forget" or "best effort" approach.