Skip to content

Commit

Permalink
feat: support joyid (#659)
Browse files Browse the repository at this point in the history
Co-authored-by: Chen Yu <keithwhisper@gmail.com>
  • Loading branch information
homura and Keith-CY committed May 6, 2024
1 parent c37d5b8 commit aef7250
Show file tree
Hide file tree
Showing 24 changed files with 986 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/tall-toes-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ckb-lumos/joyid": minor
---

feat: support joyid
48 changes: 48 additions & 0 deletions .github/workflows/experimental-joyid.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Canary
on:
push:
branches:
- experimental-joyid

permissions:
contents: write

jobs:
canary:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3

- name: Install dependencies
uses: ./.github/actions/install-deps

- name: Setup .npmrc file
uses: actions/setup-node@v3
with:
registry-url: "https://registry.npmjs.org"

- name: Experimental release
run: |
npx changeset pre exit || true
npx changeset version --snapshot experimental-joyid-$(git log -1 --pretty=format:%h)
pnpm -r publish --no-git-checks --tag experimental-joyid
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Generate commit comment
id: commit-comment
run: |
result="$(node scripts/canary-commit-comment.cjs)"
delimiter="$(openssl rand -hex 8)"
echo "result<<$delimiter" >> $GITHUB_OUTPUT
echo "$result" >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
- name: Create commit comment
uses: peter-evans/commit-comment@v2
with:
body: ${{ steps.commit-comment.outputs.result }}
token: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const scopeEnumValues = [
"runner",
"e2e-test",
"molecule",
"joyid",
];
const Configuration = {
extends: ["@commitlint/config-conventional"],
Expand Down
3 changes: 1 addition & 2 deletions examples/cardano-lock-namiwallet/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"private": true,
"name": "@lumos-examples/cardano-lock-namiwallet",
"version": "0.21.0-next.0",
"description": "",
"description": "1.0.0",
"main": "index.js",
"scripts": {
"start": "parcel index.html",
Expand Down
12 changes: 12 additions & 0 deletions examples/joyid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Lumos Works with JoyID

[JoyID](https://joy.id/) is a universal account protocol. This example shows how to use Lumos to work with JoyID by a simple CKB transfer transaction.

## Quick Start

> We should [build](..) Lumos project first before starting this example.
```
pnpm install
pnpm start
```
16 changes: 16 additions & 0 deletions examples/joyid/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Lumos & JoyID</title>
</head>
<body>
<div id="root"></div>
<script src="index.tsx" type="module"></script>
</body>
</html>
100 changes: 100 additions & 0 deletions examples/joyid/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import { connect, initConfig, signRawTransaction } from "@joyid/ckb";
import { buildTransfer, capacityOf, sendTransaction } from "./lib";
import { formatUnit, parseUnit } from "@ckb-lumos/lumos/utils";
import { createTransactionFromSkeleton } from "@ckb-lumos/lumos/helpers";
import { registerCustomLockScriptInfos } from "@ckb-lumos/lumos/common-scripts/common";
import { createJoyIDScriptInfo, getDefaultConfig } from "@ckb-lumos/joyid";

initConfig({ network: "testnet" });

const App = () => {
const [address, setAddress] = useState("");
const [balance, setBalance] = useState("-");
const [transferAddr, setTransferAddr] = useState("");
const [transferAmount, setTransferAmount] = useState("");
const [isSendingTx, setIsSendingTx] = useState(false);
const [txHash, setTxHash] = useState("");

useEffect(() => {
if (!address) return;
capacityOf(address).then((balance) => setBalance(formatUnit(balance, "ckb") + " CKB"));
}, [address]);

async function onConnect() {
const connection = await connect();
registerCustomLockScriptInfos([createJoyIDScriptInfo(connection, getDefaultConfig(false))]);
setAddress(connection.address);
}

async function transfer(): Promise<string> {
const unsigned = await buildTransfer({ amount: parseUnit(transferAmount, "ckb"), from: address, to: transferAddr });
const tx = createTransactionFromSkeleton(unsigned);

console.log("signRawTransaction: ", JSON.stringify(tx));
// @ts-ignore data2 is not defined in joyid sdk
const signed = await signRawTransaction(tx, address);
console.log("signed transaction: ", JSON.stringify(signed));
return sendTransaction(signed);
}

function onTransfer() {
if (isSendingTx) return;
setIsSendingTx(true);

transfer()
.then(setTxHash)
.finally(() => setIsSendingTx(false));
}

if (!address) {
return (
<div>
<button onClick={onConnect}>Connect</button>
</div>
);
}

if (!address.startsWith("ckt")) {
alert("The example should only be used in CKB testnet");
}

return (
<div>
<div>CKB address: {address}</div>
<div>Balance: {balance}</div>
<h2>Transfer</h2>
<div>
<label htmlFor="amount">Amount:</label>
<input
id="amount"
placeholder="Amount(CKB)"
value={transferAmount}
onChange={(e) => setTransferAmount(e.target.value)}
/>
<br />
<label htmlFor="address">Address</label>
<input
id="address"
placeholder="ckt1..."
value={transferAddr}
onChange={(e) => setTransferAddr(e.target.value)}
/>
<br />
<button onClick={onTransfer} disabled={isSendingTx}>
Transfer
</button>
<br />
{txHash && (
<a target="_blank" href={`https://pudge.explorer.nervos.org/transaction/${txHash}`}>
Check In Explorer
</a>
)}
</div>
</div>
);
};

const app = document.getElementById("root");
ReactDOM.render(<App />, app);
51 changes: 51 additions & 0 deletions examples/joyid/lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { BI, config, Indexer, RPC, helpers, commons, Transaction, Hash, BIish } from "@ckb-lumos/lumos";

export const CONFIG = config.predefined.AGGRON4;
config.initializeConfig(CONFIG);
const CKB_RPC_URL = "https://testnet.ckb.dev/rpc";
const rpc = new RPC(CKB_RPC_URL);
const indexer = new Indexer(CKB_RPC_URL);

export function asyncSleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}

export interface TransferOptions {
from: string;
to: string;
amount: BIish;
}

export async function buildTransfer(options: TransferOptions) {
let txSkeleton = helpers.TransactionSkeleton({ cellProvider: indexer });
const fromScript = helpers.parseAddress(options.from);
const fromAddress = helpers.encodeToAddress(fromScript, { config: CONFIG });
const toScript = helpers.parseAddress(options.to);
const toAddress = helpers.encodeToAddress(toScript, { config: CONFIG });
txSkeleton = await commons.common.transfer(
txSkeleton,
[fromAddress],
toAddress,
options.amount,
undefined,
undefined,
{ config: CONFIG }
);
txSkeleton = await commons.common.payFee(txSkeleton, [fromAddress], 1000, undefined, { config: CONFIG });
return txSkeleton;
}

export async function sendTransaction(tx: Transaction): Promise<Hash> {
return rpc.sendTransaction(tx, "passthrough");
}

export async function capacityOf(address: string): Promise<BI> {
const collector = indexer.collector({
lock: helpers.parseAddress(address),
});
let balance = BI.from(0);
for await (const cell of collector.collect()) {
balance = balance.add(cell.cellOutput.capacity);
}
return balance;
}
26 changes: 26 additions & 0 deletions examples/joyid/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"private": true,
"name": "@lumos-examples/joyid",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "parcel index.html",
"lint": "tsc --noEmit"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"@ckb-lumos/lumos": "canary",
"@ckb-lumos/joyid": "canary",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
"@joyid/ckb": "^0.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"parcel": "^2.9.3"
}
}
10 changes: 10 additions & 0 deletions examples/joyid/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"lib": ["dom"],
"jsx": "react",
"module": "CommonJS",
"skipLibCheck": true,
"esModuleInterop": true,
"target": "ES2020"
}
}
2 changes: 2 additions & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"@parcel/config-default": "^2.8.0",
"@parcel/transformer-js": "^2.8.0",
"@parcel/transformer-react-refresh-wrap": "^2.8.0",
"assert": "^2.0.0",
"buffer": "^5.5.0",
"constants-browserify": "^1.0.0",
"crypto-browserify": "^3.12.0",
"events": "^3.1.0",
"path-browserify": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/pw-lock-metamask/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@lumos-examples/pw-lock-metamask",
"version": "0.21.0-next.0",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion examples/secp256k1-multisig-transfer/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@lumos-examples/secp256k1-multisig-transfer",
"version": "0.21.0-next.0",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion examples/secp256k1-transfer/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@lumos-examples/secp256k1-transfer",
"version": "0.21.0-next.0",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions packages/joyid/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib
31 changes: 31 additions & 0 deletions packages/joyid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# `@ckb-lumos/joyid`

A module for working with JoyID.

> Note: JoyID does not support working with other lock scripts in a transaction yet.
## Usage

To use `@ckb-lumos/joyid`, the `@joyid/ckb` package must be installed.

```sh
npm install @joyid/ckb #@0.0.6
```

```js
import { createJoyIDScriptInfo, getDefualtConfig } from "@ckb-lumos/joyid";
import { connect } from "@joyid/ckb";
import { registerCustomLockScriptInfos } from "@ckb-lumos/lumos/common-scripts/common";

// step 1. connect to JoyID
const connection = await connect();

// step 2. create JoyID script info, we can use the helper function getDefaultConfig to generate a default config
const joyIDScriptInfo = createJoyIDScriptInfo(
connection,
getDefaultConfig(false /* isMainnet */)
);

// step 3. register JoyID script info into Lumos
registerCustomLockScriptInfos(joyIDScriptInfo);
```
Loading

1 comment on commit aef7250

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 New canary release: 0.0.0-canary-aef7250-20240506034257

npm install @ckb-lumos/lumos@0.0.0-canary-aef7250-20240506034257

Please sign in to comment.