Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add next-js template for offckb create #326

Merged
merged 1 commit into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/next-js-template/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/build
/target
/tests/failed_txs
15 changes: 15 additions & 0 deletions examples/next-js-template/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[workspace]
resolver = "2"

members = [
# Please don't remove the following line, we use it to automatically
# detect insertion point for newly generated crates.
# @@INSERTION_POINT@@
"contracts/hello-world",
"tests",
]

[profile.release]
overflow-checks = true
strip = true
codegen-units = 1
115 changes: 115 additions & 0 deletions examples/next-js-template/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# We cannot use $(shell pwd), which will return unix path format on Windows,
# making it hard to use.
cur_dir = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))

TOP := $(cur_dir)
# RUSTFLAGS that are likely to be tweaked by developers. For example,
# while we enable debug logs by default here, some might want to strip them
# for minimal code size / consumed cycles.
CUSTOM_RUSTFLAGS := --cfg debug_assertions
# Additional cargo args to append here. For example, one can use
# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to
# stdout in unit tests
CARGO_ARGS :=
MODE := release
# Tweak this to change the clang version to use for building C code. By default
# we use a bash script with somes heuristics to find clang in current system.
CLANG := $(shell $(TOP)/scripts/find_clang)
# When this is set, a single contract will be built instead of all contracts
CONTRACT :=
# By default, we would clean build/{release,debug} folder first, in case old
# contracts are mixed together with new ones, if for some reason you want to
# revert this behavior, you can change this to anything other than true
CLEAN_BUILD_DIR_FIRST := true
BUILD_DIR := build/$(MODE)

# Pass setups to child make processes
export CUSTOM_RUSTFLAGS
export TOP
export CARGO_ARGS
export MODE
export CLANG
export BUILD_DIR

default: build test

build:
@if [ "x$(CLEAN_BUILD_DIR_FIRST)" = "xtrue" ]; then \
echo "Cleaning $(BUILD_DIR) directory..."; \
rm -rf $(BUILD_DIR); \
fi
mkdir -p $(BUILD_DIR)
@set -eu; \
if [ "x$(CONTRACT)" = "x" ]; then \
for contract in $(wildcard contracts/*); do \
$(MAKE) -e -C $$contract build; \
done; \
else \
$(MAKE) -e -C contracts/$(CONTRACT) build; \
fi

# Run a single make task for a specific contract. For example:
#
# make run CONTRACT=stack-reorder TASK=adjust_stack_size STACK_SIZE=0x200000
TASK :=
run:
$(MAKE) -e -C contracts/$(CONTRACT) $(TASK)

# test, check, clippy and fmt here are provided for completeness,
# there is nothing wrong invoking cargo directly instead of make.
test:
cargo test $(CARGO_ARGS)

check:
cargo check $(CARGO_ARGS)

clippy:
cargo clippy $(CARGO_ARGS)

fmt:
cargo fmt $(CARGO_ARGS)

# Arbitrary cargo command is supported here. For example:
#
# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly"
#
# Invokes:
# cargo expand --ugly
CARGO_CMD :=
cargo:
cargo $(CARGO_CMD) $(CARGO_ARGS)

clean:
rm -rf build
cargo clean

TEMPLATE_TYPE := --git
TEMPLATE_REPO := https://github.com/cryptape/ckb-script-templates
CRATE :=
TEMPLATE := contract
DESTINATION := contracts
generate:
@set -eu; \
if [ "x$(CRATE)" = "x" ]; then \
cargo generate $(TEMPLATE_TYPE) $(TEMPLATE_REPO) $(TEMPLATE) \
--destination $(DESTINATION); \
GENERATED_DIR=$$(ls -dt $(DESTINATION)/* | head -n 1); \
sed "s,@@INSERTION_POINT@@,@@INSERTION_POINT@@\n \"$$GENERATED_DIR\"\,," Cargo.toml > Cargo.toml.new; \
mv Cargo.toml.new Cargo.toml; \
else \
cargo generate $(TEMPLATE_TYPE) $(TEMPLATE_REPO) $(TEMPLATE) \
--destination $(DESTINATION) \
--name $(CRATE); \
sed '/@@INSERTION_POINT@@/s/$$/\n "$(DESTINATION)\/$(CRATE)",/' Cargo.toml > Cargo.toml.new; \
mv Cargo.toml.new Cargo.toml; \
fi

prepare:
rustup target add riscv64imac-unknown-none-elf

# Generate checksum info for reproducible build
CHECKSUM_FILE := build/checksums-$(MODE).txt
checksum: build
sha256sum build/$(MODE)/* > $(CHECKSUM_FILE)

.PHONY: build test check clippy fmt cargo clean prepare checksum
118 changes: 118 additions & 0 deletions examples/next-js-template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# offckb-template

This is a Minimal Template for CKB Full-Stack Dapps generated by [offckb](https://github.com/RetricSu/offckb).

Offckb does not do the magic. It just wraps the new CKB smart contract template and the CKB javascript Dapp framework into one mono-repo. Under the hook, it uses:

- [ckb-scripts-template](https://github.com/cryptape/ckb-script-templates) for smart contract development
- [next-js](https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app) and [Lumos](https://github.com/ckb-js/lumos) for frontend development

## Smart contract development

By default, this template comes with a single simple smart contract `hello-world`: `contracts/hello-world/src/main.rs`.

The smart contract is written in Rust lang. In order to develop, the following dependencies are required:

- `git`, `make`, `sed`, `bash`, `sha256sum` and others Unix utilities.
- `Rust` with `riscv64 target`: `rustup target add riscv64imac-unknown-none-elf`
- `Clang 16+`
- `cargo-generate`

Check out the ckb-script-templates for more [detail](https://github.com/cryptape/ckb-script-templates/blob/main/README.md#dependencies)

### Usage

add a new smart-contract:

```sh
make generate
```

build smart-contract:

```sh
make build
```

run test:

```sh
make test
```

For more detail, check out [ckb-script-templates](https://github.com/cryptape/ckb-script-templates)

## dApp frontend development

first, enter the frontend workspace:

```sh
cd frontend
```

start the app:

```sh
npm i && npm run dev
```

change the CKB blockchain network:

edit `.env` file:

```bash
NEXT_PUBLIC_NETWORK=devnet # devnet, testnet or mainnet
```

## Deploy to devnet/testnet with offckb

Once you build your smart contracts, you can deploy them to CKB blockchain with [ckb-cli](https://github.com/nervosnetwork/ckb-cli) or any other tools.

If you want to test them in devnet/testnet blockchain, then `offckb` might be the ideal selection.

`offckb` will look for the `offckb.config.ts` file to read config information. so you will need to enter the frontend workspace to do the instruction:

```sh
cd frontend
offckb deploy --network devnet
```

If successfully deployed, you will see the deploy script info for your smart contract recorded in the `offckb.config.ts` file. You can then directly import and use your smart contract in your frontend Dapp like this:

```ts
import offckb from "offckb.config";
import { CellDep } from "@ckb-lumos/lumos";

const lumosConfig = offckb.lumosConfig;
const myContractDep: CellDep = {
outPoint: {
txHash: lumosConfig.SCRIPTS.YOUR_SCRIPT_NAME!.TX_HASH,
index: lumosConfig.SCRIPTS.YOUR_SCRIPT_NAME!.INDEX,
},
depType: lumosConfig.SCRIPTS.YOUR_SCRIPT_NAME!.DEP_TYPE,
};
```

Every time you deploy a new version of your smart contracts, those script infos will be updated by `offckb` in the `offckb.config.ts` and work out-of-box in your frontend.

You can also deploy smart contracts to the CKB Testnet like this:

```sh
cd frontend
offckb deploy --network testnet
```

and start your frontend Dapp targeting Testnet:

edit `.env` file:

```bash
NEXT_PUBLIC_NETWORK=testnet # devnet, testnet or mainnet
```

```bash
cd frontend
npm run dev
```

Note that the `mainnet` network is not supported in `offckb` since `offckb` is focusing on building a friendly development environment for CKB. To gain better security, it is recommended to use production tools like [ckb-cli](https://github.com/nervosnetwork/ckb-cli) to deploy smart contracts and do transactions for the CKB mainnet.
2 changes: 2 additions & 0 deletions examples/next-js-template/contracts/hello-world/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/build
/target
7 changes: 7 additions & 0 deletions examples/next-js-template/contracts/hello-world/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "hello-world"
version = "0.1.0"
edition = "2021"

[dependencies]
ckb-std = "0.15.1"
76 changes: 76 additions & 0 deletions examples/next-js-template/contracts/hello-world/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# We cannot use $(shell pwd), which will return unix path format on Windows,
# making it hard to use.
cur_dir = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))

TOP := $(cur_dir)
# RUSTFLAGS that are likely to be tweaked by developers. For example,
# while we enable debug logs by default here, some might want to strip them
# for minimal code size / consumed cycles.
CUSTOM_RUSTFLAGS := --cfg debug_assertions
# RUSTFLAGS that are less likely to be tweaked by developers. Most likely
# one would want to keep the default values here.
FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs $(CUSTOM_RUSTFLAGS)
# Additional cargo args to append here. For example, one can use
# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to
# stdout in unit tests
CARGO_ARGS :=
MODE := release
# Tweak this to change the clang version to use for building C code. By default
# we use a bash script with somes heuristics to find clang in current system.
CLANG := $(shell $(TOP)/scripts/find_clang)
# When this is set to some value, the generated binaries will be copied over
BUILD_DIR :=
# Generated binaries to copy. By convention, a Rust crate's directory name will
# likely match the crate name, which is also the name of the final binary.
# However if this is not the case, you can tweak this variable. As the name hints,
# more than one binary is supported here.
BINARIES := $(notdir $(shell pwd))

ifeq (release,$(MODE))
MODE_ARGS := --release
endif

default: build test

build:
RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" \
cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS)
@set -eu; \
if [ "x$(BUILD_DIR)" != "x" ]; then \
for binary in $(BINARIES); do \
echo "Copying binary $$binary to build directory"; \
cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \
done \
fi

# test, check, clippy and fmt here are provided for completeness,
# there is nothing wrong invoking cargo directly instead of make.
test:
cargo test $(CARGO_ARGS)

check:
cargo check $(CARGO_ARGS)

clippy:
cargo clippy $(CARGO_ARGS)

fmt:
cargo fmt $(CARGO_ARGS)

# Arbitrary cargo command is supported here. For example:
#
# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly"
#
# Invokes:
# cargo expand --ugly
CARGO_CMD :=
cargo:
cargo $(CARGO_CMD) $(CARGO_ARGS)

clean:
cargo clean

prepare:
rustup target add riscv64imac-unknown-none-elf

.PHONY: build test check clippy fmt cargo clean prepare
7 changes: 7 additions & 0 deletions examples/next-js-template/contracts/hello-world/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# hello-world

TODO: Write this readme

*This contract was bootstrapped with [ckb-script-templates].*

[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates
18 changes: 18 additions & 0 deletions examples/next-js-template/contracts/hello-world/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![no_std]
#![cfg_attr(not(test), no_main)]

#[cfg(test)]
extern crate alloc;

#[cfg(not(test))]
use ckb_std::default_alloc;
#[cfg(not(test))]
ckb_std::entry!(program_entry);
#[cfg(not(test))]
default_alloc!();

pub fn program_entry() -> i8 {
ckb_std::debug!("Hello world! This is a sample contract!");

0
}
1 change: 1 addition & 0 deletions examples/next-js-template/frontend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_NETWORK=devnet
3 changes: 3 additions & 0 deletions examples/next-js-template/frontend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
Loading