Skip to content

Commit 632d792

Browse files
committed
feat(sudt): sudt create, update and detail
1 parent 95a0924 commit 632d792

File tree

6 files changed

+285
-40
lines changed

6 files changed

+285
-40
lines changed

package-lock.json

Lines changed: 92 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/samples/sudt/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"build:watch": "tsc -w",
77
"start:prod": "node ./dist/main.js",
88
"test": "jest",
9-
"doc": "typedoc"
9+
"doc": "typedoc",
10+
"typeorm": "typeorm-ts-node-commonjs"
1011
},
1112
"dependencies": {
1213
"@ckb-js/kuai-core": "0.0.1-alpha.2",
@@ -15,7 +16,9 @@
1516
"@ckb-lumos/lumos": "0.20.0",
1617
"http-errors": "2.0.0",
1718
"koa": "2.14.1",
18-
"koa-body": "6.0.1"
19+
"koa-body": "6.0.1",
20+
"mysql2": "3.6.1",
21+
"typeorm": "0.3.17"
1922
},
2023
"devDependencies": {
2124
"ts-node": "10.9.1",

packages/samples/sudt/src/controllers/sudt.controller.ts

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
import type { HexString, Hash } from '@ckb-lumos/base'
2-
import { BaseController, Controller, Body, Post } from '@ckb-js/kuai-io'
32
import { ActorReference } from '@ckb-js/kuai-models'
4-
import { BadRequest } from 'http-errors'
3+
import { BadRequest, NotFound } from 'http-errors'
54
import { SudtModel, appRegistry } from '../actors'
65
import { Tx } from '../views/tx.view'
76
import { getLock } from '../utils'
8-
import { SudtResponse } from '../response'
7+
import { BaseController, Body, Controller, Get, Param, Post, Put } from '@ckb-js/kuai-io'
8+
import { SudtResponse } from '../../response'
9+
import { CreateTokenRequest } from '../dto/create-token.dto'
10+
import { DataSource, QueryFailedError } from 'typeorm'
11+
import { Token } from '../entities/token.entity'
12+
import { Account } from '../entities/account.entity'
13+
import { tokenEntityToDto } from '../dto/token.dto'
914

1015
@Controller('sudt')
1116
export default class SudtController extends BaseController {
17+
#explorerHost = process.env.EXPLORER_HOST || 'https://explorer.nervos.org'
18+
constructor(private _dataSource: DataSource) {
19+
super()
20+
}
21+
1222
@Post('/send')
1323
async send(
1424
@Body() { from, to, amount, typeArgs }: { from: string[]; to: string; amount: HexString; typeArgs: Hash },
@@ -39,4 +49,58 @@ export default class SudtController extends BaseController {
3949
)
4050
return SudtResponse.ok(await Tx.toJsonString(result))
4151
}
52+
53+
@Post('/token')
54+
async createToken(@Body() req: CreateTokenRequest) {
55+
let owner = await this._dataSource.getRepository(Account).findOneBy({ address: req.account })
56+
if (!owner) {
57+
owner = await this._dataSource
58+
.getRepository(Account)
59+
.save(this._dataSource.getRepository(Account).create({ address: req.account }))
60+
}
61+
62+
try {
63+
const token = await this._dataSource
64+
.getRepository(Token)
65+
.save(this._dataSource.getRepository(Token).create({ ...req, ownerId: owner.id }))
66+
return new SudtResponse('201', { url: `${this.#explorerHost}/transaction/${token.typeId}` })
67+
} catch (e) {
68+
if (e instanceof QueryFailedError) {
69+
switch (e.driverError.code) {
70+
case 'ER_DUP_ENTRY':
71+
return SudtResponse.err('409', { message: 'Token already exists' })
72+
}
73+
}
74+
75+
console.error(e)
76+
}
77+
}
78+
79+
@Put('/token')
80+
async updateToken(@Body() req: CreateTokenRequest) {
81+
const token = await this._dataSource.getRepository(Token).findOneBy({ typeId: req.typeId })
82+
if (token) {
83+
await this._dataSource.getRepository(Token).save({ ...token, ...req })
84+
}
85+
86+
return new SudtResponse('201', {})
87+
}
88+
89+
@Get('/token/:typeId')
90+
async getToken(@Param('typeId') typeId: string) {
91+
const token = await this._dataSource.getRepository(Token).findOneBy({ typeId })
92+
93+
if (token) {
94+
return SudtResponse.ok(tokenEntityToDto(token, '0', this.#explorerHost))
95+
} else {
96+
throw new NotFound()
97+
}
98+
}
99+
100+
@Get('/tokens')
101+
async listTokens() {
102+
const tokens = await this._dataSource.getRepository(Token).find()
103+
104+
return SudtResponse.ok(tokens.map((token) => tokenEntityToDto(token, '0', this.#explorerHost)))
105+
}
42106
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Token } from '../entities/token.entity'
2+
3+
export interface TokenResponse {
4+
symbol: string
5+
name: string
6+
amount: string
7+
decimal: number
8+
description: string
9+
website: string
10+
icon: string
11+
explorerUrl: string
12+
}
13+
14+
export const tokenEntityToDto = (token: Token, amount: string, explorerHost: string): TokenResponse => {
15+
return {
16+
symbol: token.name,
17+
name: token.name,
18+
amount,
19+
decimal: token.decimal,
20+
description: token.description ?? '',
21+
website: token.website,
22+
icon: token.icon,
23+
explorerUrl: `${explorerHost}/sudt/${token.typeId}`,
24+
}
25+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Column, CreateDateColumn, Entity, Index, PrimaryGeneratedColumn, Unique, UpdateDateColumn } from 'typeorm'
2+
3+
@Entity()
4+
export class Token {
5+
@PrimaryGeneratedColumn()
6+
id!: number
7+
8+
@Column()
9+
name!: string
10+
11+
@Column({ default: 18 })
12+
decimal!: number
13+
14+
@Column()
15+
description?: string
16+
17+
@Column({ default: '' })
18+
website!: string
19+
20+
@Column({ default: '' })
21+
icon!: string
22+
23+
@Column({ default: '' })
24+
txHash?: string
25+
26+
@Column()
27+
@Index()
28+
ownerId!: number
29+
30+
@Column()
31+
@Unique('uniq_type_id', ['typeId'])
32+
typeId!: string
33+
34+
@Column()
35+
@Unique('uniq_args', ['args'])
36+
args!: string
37+
38+
@CreateDateColumn()
39+
createdAt!: Date
40+
41+
@UpdateDateColumn()
42+
updatedAt!: Date
43+
}

0 commit comments

Comments
 (0)