0.1.1 • Published 2 years ago

web3_crs v0.1.1

Weekly downloads
-
License
-
Repository
gitlab
Last release
2 years ago

CRS

Registerars and resolves of unique names for worlds and communities in VeVerse Metaverse and LE7EL. It's an adapted fork of Ethereum Name Service.

JS

All web3 interactions are using default window.ethereum web3 provider.

Installation

`npm install web3_crs`

Usage

`import { controller, utils, artifacts, contracts } from "web3_crs"`

Controller

The main interface for interaction with CRS NFTs. In all methods, instead of preconfigured contract_key you can pass address of a compliant controller smart contract e.g. 0xFf9967Eaf61C2f0901A89Bf3F2D9A13DcAa3E3aa.

controllerAddress()

Get address of controller in a currently selected network (if deployed).

`await controller.controllerAddress()`

available(string name) returns (boolean promise)

Checks if specific name wasn't registered already.

```js
await controller.available("VeVerse")
```

makeCommitment(string name, address owner, bytes32 secret, string contract_key) returns (bytes32 promise)

Generates commitment hash for the provided secret.

```js
const owner = "0x0000000000000000000000000000000000000000"
const secret = ethers.utils.randomBytes(32)
const commitment = await controller.makeCommitment("VeVerse", owner, secret, "vcr_controller")
```

commit(bytes32 commitment, string contract_key) returns (transaction promise)

Start registration of CRS name, there should be 60 seconds delay between commitment and registration to prevent race conditions.

```js
await controller.commit(commitment, "vcr_controller")
```

register(string name, address owner, integer duration, bytes32 secret, string contract_key) returns (transaction promise)

All variables should be the same as used on makeCommitment step. Some CRS may require approval of a relevant ERC20 token, before running this transaction. This can be done with utils.erc20Approve call.

```js
const owner = "0x0000000000000000000000000000000000000000"
const duration = 31556952 // 1 year in seconds
await controller.register("VeVerse", owner, duration, secret, "vcr_controller")
```

rentPrice(string name, integer duration, string contract_key) returns (address, BigNumber promise)

Checks if there is any fee to register / renew this CRS record, returns contract address of ERC20 token and the fee amount. In case address is zero, it means that fee should be paid in gas coin, which is managed by register automatically, call erc20Approve if there is non-zero fee in ERC20 token.

Utils

erc20Approve(address token_address, address spender_address, BigNumber amount)

Registration may require fees to be paid in native ERC20 token, use this method to authorize such payment before registration. Check BigNumber to pass token amount. You only need this if, controller.rentPrice(...) returns non-zero address as first variable and greater than 0 on second variable e.g.

```js
controller.rentPrice(name, duration, "vcr_controller")
  .then((response) => {
    const token = response[0]
    const amount = response[1]
    if (token === ADDRESS_ZERO || response[1].isZero()) {
      return register(name, accounts[0], duration, secret, controller)
    } else {
      return controllerAddress(controller)
        .then((spender) => {
          return erc20Approve(token, spender, amount)
            .then(tr => provider.waitForTransaction(tr.hash))
            .then(_ => register(name, accounts[0], duration, secret, controller))
        })
    }
  })
```

Artifacts

Provides access to low level data (abi, bytecode etc) for the core smart contracts with the following keys:

  • controller
  • registry
  • nft
  • resolver

For instance, to access controller abi, you can use artifacts.controller.abi.

Contracts

Returns deployment addresses of smart contracts, can be accesses by using the following format: contracts[network_id][contract_key]. To get VCR controller on Rinkeby network you can call contracts["4"]["vcr_controller"]. The following contract keys are supported:

  • registry
  • resolver
  • l7l_controller
  • l7l_nft
  • vcr_controller
  • vcr_nft
  • vcr_token

Smart contracts

CRSRegistry.sol

Implementation of the CRS Registry, the central contract used to look up resolvers and owners for domains.

BaseNFT.sol

Implementation of ERC721 standard for CRS NFTs, this smart contract is also an owner of CRSRegistry. Protected functions are called through Controller contact, check it's public interface(#NFT controller interface).

CRS Registry interface

The CRS registry is a single central contract that provides a mapping from world names to owners and resolvers, as described in EIP 137.

The CRS operates on 'nodes' instead of human-readable names; a human readable name is converted to a node using the namehash algorithm, which is as follows:

def namehash(name):
  if name == '':
    return '\0' * 32
  else:
    label, _, remainder = name.partition('.')
    return sha3(namehash(remainder) + sha3(label))

The registry's interface is as follows:

owner(bytes32 node) constant returns (address)

Returns the owner of the specified node.

resolver(bytes32 node) constant returns (address)

Returns the resolver for the specified node.

setOwner(bytes32 node, address owner)

Updates the owner of a node. Only the current owner may call this function.

setSubnodeOwner(bytes32 node, bytes32 label, address owner)

Updates the owner of a subnode. For instance, the owner of "foo.com" may change the owner of "bar.foo.com" by calling setSubnodeOwner(namehash("foo.com"), sha3("bar"), newowner). Only callable by the owner of node.

setResolver(bytes32 node, address resolver)

Sets the resolver address for the specified node.

NFT controller interface

Controller smart contract is used to change global NFT settings.

available(string memory _name)

Checks availability of name in namespace.

rentPrice(string memory _name, uint _duration)

Calculate price in ERC20 or gas coin for registering CRS record.

makeCommitment(string memory _name, address _owner, bytes32 _secret)

Generate commitment hash to reserve name for registration, having hidden secret to confirm ownership.

commit(bytes32 _commitment)

Start registration process, with commitment hash returned by makeCommitment.

register(string calldata _name, address _owner, uint _duration, bytes32 _secret)

Finish registration process after commitment maturation, use secret hash from makeCommitment.

renew(string calldata _name, uint _duration)

Extend lease for a currently owned NFT for CRS name.

changeTokenURIProxy(address _proxy)

Owner can update proxy address to resolve NFT metadata.

withdraw(address _paymentToken)

Withdraw registration fees in ERC20 token or gas coin (address(0) as _paymentToken).

Resolver interface

Resolver smart contract is modular, with DefaultResolver having all modules enabled. Projects can implement own resolves using modules from contracts/resolver/profile. It's used as on-chain storage for different kind of data related to specific CRS record.

setApprovalForAll(address operator, bool approved)

Allow / Revoke 3rd party address to change resolver data records, keep in mind that it doesn't affect ProxyConfigResolver which uses permissionless scoped storage.

ProxyConfigResolver

ProxyConfig can be used by any 3rd party to assign proxy smart contract which will resolve into content attached to specific CRS record. It's main difference from the rest of resolvers modules, is that it has scoped storage which doesn't require approval by the CRS owner.

Web3 games can use this module methods to store their own metadata for CRS record. Proxy contract can be as simple as definition of specific getter / setter methods (e.g. tokenURI(uint256), setTokenURI(uint256,string), avatar(uint256), setAvatar(uint256,string)) with local on-chain storage for this data.

proxyConfig(bytes32 node, address controller, bytes4 selector)

Get proxy smart contract for controller and selector. Methods of this contract should be called for final data resolution. When proxy smart contract defines only one getter method, it's recommended to use that method selector (e.g. bytes4(keccak256("tokenURI(uint256)"))). Default proxy contracts should use bytes4(0) selector.

setProxyConfig(bytes32 node, address controller, bytes4 selector, address proxy)

Change address of proxy smart contract with specific metadata attached to CRS record by controller party. Individual proxy contracts can be separated by selector which are either solidity method selectors or by using any other system suitable for controller party. Default proxy contracts should use bytes4(0) selector.

NFT interface

Extends ERC721 and Ownable standard contracts. Owner can assign / revoke controllers, change minting fee and update the default resolver contract address.

addController(address _controller)

Add smart contract which can register, renew and use other restricted methods related to CRS management.

removeController(address _controller)

Revoke controller access from smart contract.

setResolver(address _resolver)

Change default resolver smart contract.

setRoyalties(address _beneficiary, uint256 _amount, address _token, address _forAddress)

Change royalties charged in ERC20 or gas coin, use address(0) for _token for gas coin. Individual royalties can be set with _forAddress setting, pass address(0) for defaults.

Getting started

Install packages

$ npm install --dev

Install Hardhat

$ npm install --save-dev hardhat

Launch the local Ethereum client e.g. Ganache:

Integration

Run webpack development server: npx webpack serve --open

Check http://localhost:8080/ for CRS registration UX.

Implementation example entrypoints can be found here: src/index.js and dist/index.html.

Testing

Install local ganache: npm install --global ganache

Run it in cli: ganache, you may need to change network_id for develop network in truffle-config.js

Run tests with truffle: yarn test

Verification

To try out Etherscan verification, you first need to deploy a contract to an Ethereum network that's supported by Etherscan, such as Rinkeby.

In this project, copy the .example file to a file named .secret, and then edit it to fill in the details. Enter your Etherscan API key, your Rinkeby node URL (eg from Infura), and the private key of the account which will send the deployment transaction. With a valid .secret file in place, first deploy your contract:

npx hardhat run --network live_rinkeby scripts/1_deploy_all.js

Then, copy the deployment address and paste it in to replace DEPLOYED_CONTRACT_ADDRESS in this command:

npx hardhat verify --network live_rinkeby DEPLOYED_CONTRACT_ADDRESS ...CONSTRUCTOR_ARGS

Deployments

Rinkeby

CRSRegistry deployed to: 0xA2d79B9a3613C79e3a68FcBb67A5AB488143Ad66 DefaultResolver deployed to: 0x3C1D75Ab465225A1384A2B73E4F60A597c6B6f9f L7LImplementation deployed to: 0xF9937871F1a0F3d2da54021Bbc36A9DF01f3D05e L7LController deployed to: 0xFf9967Eaf61C2f0901A89Bf3F2D9A13DcAa3E3aa VCRImplementation deployed to: 0xe2DF3475b22d0f0da4aC415717d30Ac79F31e3C6 VCRController deployed to: 0x3C8a2a895A92147f2b49d8bc3fa08a8F3F624E74 MetadataProxy (VCR) deployed to: 0x92dbe7fbad5e5baae1f288ada9eaa4554f9fecaf