This is the minimum viable product(MVP) designed to demonstrate Kuai's ability to manipulate a group of cells on the Nervos Common Knowledge Base (CKB).
The Kuai MVP DApp is a partially implemented data.did.id, which serves as a decentralized account profile. In comparison to the fully implemented version, the Kuai MVP DApp focuses solely on on- and off-chain data management. On-chain state verification will be supported in the next stage of development.
You can find an online preview of the Kuai MVP DApp at https://kuai-mvp-dapp-ui.vercel.app/.
A comprehensive guide is available at docs/tutorials/mvp-dapp.md
The magical get
could be found at store model of Kuai
public load(path?: string) {
let local = {}
const customizer = (objValue: StructSchema, srcValue: StructSchema) => {
if (Array.isArray(objValue)) {
return objValue.concat(srcValue)
}
}
Object.values(this.states).forEach((state) => {
local = mergeWith(local, state, customizer)
})
if (path) {
return get(local, path, null)
}
return local
}
The magical set
could be found at store model of Kuai
initOnChain(value: GetStorageStruct<StructSchema>): GetOnChainStorage<StructSchema> {
const res: StorageSchema<string> = {}
if ('data' in value) {
const { offset, hexString } = this.serializeField('data', value.data)
res.data = `0x${offset ? '0'.repeat(offset * ByteCharLen) : ''}${hexString.slice(2)}`
}
if ('witness' in value) {
const { offset, hexString } = this.serializeField('witness', value.witness)
res.witness = `0x${offset ? '0'.repeat(offset * ByteCharLen) : ''}${hexString.slice(2)}`
}
if ('lockArgs' in value) {
const { offset, hexString } = this.serializeField('lockArgs', value.lockArgs)
res.lockArgs = `0x${offset ? '0'.repeat(offset * ByteCharLen) : ''}${hexString.slice(2)}`
}
if ('typeArgs' in value) {
const { offset, hexString } = this.serializeField('typeArgs', value.typeArgs)
res.typeArgs = `0x${offset ? '0'.repeat(offset * ByteCharLen) : ''}${hexString.slice(2)}`
}
return res as GetOnChainStorage<StructSchema>
}
With the power of magical get
and set
, the business model record
, representing a storage with a custom schema, has the ability to manipulate cells by users' mind
The main code of business logic could be found at record model of mvp dapp
update(newValue: StoreType['data']) {
const inputs = Object.values(this.chainData)
if (!inputs.length) throw new InternalServerError('No mvp cell to set value')
const { data } = this.initOnChain({ data: newValue })
const outputCapacity = inputs
.reduce((pre: BI, cur) => pre.add(cur.cell.cellOutput.capacity), BI.from(0))
.sub(TX_FEE)
if (outputCapacity.lt('6100000000')) throw new Error('not enough capacity')
const outputs: Cell[] = [
{
cellOutput: {
...inputs[0]!.cell.cellOutput,
capacity: outputCapacity.toHexString(),
},
data: `${inputs[0]!.cell.data.slice(0, 2 + this.schemaOption!.data.offset * 2)}${data.slice(
2 + this.schemaOption!.data.offset * 2,
)}`,
},
]
return {
inputs: inputs.map((v) => v.cell),
outputs: outputs,
}
}
TODO: the update
method, which returns inputs/outputs
, should be delivered in store model
natively because inputs/outputs
is the only meaningful result of a modification.
With the help of get
and update
, the following workflow is feasible
- dump the entire state into local by
load()
; - manipulate on the local state;
- generate cell transition from
prev state
tonew state
byupdate()
. - transform the cell transition into a transaction by view layer, tx.view in this case.
It's quite similar to the setState method in React. No matter how many updates are scheduled by setState
, only the final state will be rendered in a frame.
- manipulate states on several cells
- load and merge a global state from cells;
- locate the correct cell on updating state
- implement the
contract model
based onstore model
: ckb-js#3 - declare models by decorator with parameters: as https://github.com/ckb-js/kuai/blob/develop/packages/models/src/examples/dapp/actors/child.ts#L4
- instantiate models on demand: ckb-js#160
- support declarative routes: ckb-js#159
CKB Node and Redis Service are required in this MVP.
- Mainnet: https://docs.nervos.org/docs/basics/guides/mainnet
- Testnet: https://docs.nervos.org/docs/basics/guides/testnet
- Devnet: https://docs.nervos.org/docs/basics/guides/devchain
- Mainnet RPC endpoint: https://mainnet.ckb.dev/rpc
- Testnet RPC endpoint: https://testnet.ckb.dev/rpc
Follow ckb-js#306 to deploy your own contract. Or
The deployment information located at mvp-dapp/contract/deployed_demo
, rename it to mvp-dapp/contract/deployed
to connect to
$ git clone https://github.com/ckb-js/kuai.git
$ cd kuai
$ npm i
$ npm run build
- run the mvp dapp in develop mode
$ cd ./packages/samples/mvp-dapp
$ npm run dev
- run the mvp dapp in production mode
$ cd ./packages/samples/mvp-dapp
$ npm run build
# Service is expected to run on port 3000
$ npm run start:prod