Skip to main content
DEVNET

This functionality is only available on dev-net

DEVELOPMENT

This functionality is in development

info

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.

info

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.

info

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 the index.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 = «...»`
note

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 containing off_chain_logic.ref.

    • Hence the contract-template-id (the hash of its ContractTree), which is also the contract-module-id, covers the off_chain_logic.ref (hash).

    • Because the ContractTree of a smart contract instance is a superset of the ContractTree 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).

info

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.

DEVELOPMENT

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 the cweb-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.

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.

DEVELOPMENT

In a future version, the interpreter_id might be automatically selected based on the @coinweb/contract-kit version.

note

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.

DEVELOPMENT

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).

warning

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.

NEXT

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 (or onchain.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).

DEVELOPMENT

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 install @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 into node_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 parent node_modules folder.
      • Renaming the package name to its "contract-module-alias" package.json field, then removing "contract-module-alias" package.json field and removing index.js file, then, processing the package again (cweb-tool pack) produces the same package as before.

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 the lib/ 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 a cli facade to the current implemented Coinweb tool.

Testing:

DEVELOPMENT

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.

note

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 a wallet on wallet-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 the package.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 like uglifyjs 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 the index.js file.

  • audit: it checks that a set of "contract-modules" from a node_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", running npx 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 the package.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 from node_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 and lib/index.d.ts files.
  • it will hash all the files to be published (i.e lib/** and package.json) to define the off-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 the off-chain-logic-id as the contract-template off_chain_logic.ref file; create the contract-template's ContractTree. - hash the ContractTree to find out what would be the contract-template's id; and rename the package to this id (prepended by cweb_).
  • create lib/index.js and lib/index.d.ts:
    • they should rexport everything from lib/onchain.js and lib/off-chain.js (and their .d.ts version).
    • they should define the const hash ids used (CONTRACT_TEMPLATE, OFF_LOGIC_ID and INTERPRETER_ID ).

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 the wallet-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 define ContractRefV0, and with those CallOp 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 its ContractTree 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.

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.