Skip to content

Commit

Permalink
feat(sudt): sudt create, update and detail
Browse files Browse the repository at this point in the history
  • Loading branch information
Daryl-L committed Oct 12, 2023
1 parent 95a0924 commit 632d792
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 40 deletions.
93 changes: 92 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions packages/samples/sudt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"build:watch": "tsc -w",
"start:prod": "node ./dist/main.js",
"test": "jest",
"doc": "typedoc"
"doc": "typedoc",
"typeorm": "typeorm-ts-node-commonjs"
},
"dependencies": {
"@ckb-js/kuai-core": "0.0.1-alpha.2",
Expand All @@ -15,7 +16,9 @@
"@ckb-lumos/lumos": "0.20.0",
"http-errors": "2.0.0",
"koa": "2.14.1",
"koa-body": "6.0.1"
"koa-body": "6.0.1",
"mysql2": "3.6.1",
"typeorm": "0.3.17"
},
"devDependencies": {
"ts-node": "10.9.1",
Expand Down
70 changes: 67 additions & 3 deletions packages/samples/sudt/src/controllers/sudt.controller.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import type { HexString, Hash } from '@ckb-lumos/base'
import { BaseController, Controller, Body, Post } from '@ckb-js/kuai-io'
import { ActorReference } from '@ckb-js/kuai-models'
import { BadRequest } from 'http-errors'
import { BadRequest, NotFound } from 'http-errors'
import { SudtModel, appRegistry } from '../actors'
import { Tx } from '../views/tx.view'
import { getLock } from '../utils'
import { SudtResponse } from '../response'
import { BaseController, Body, Controller, Get, Param, Post, Put } from '@ckb-js/kuai-io'
import { SudtResponse } from '../../response'
import { CreateTokenRequest } from '../dto/create-token.dto'
import { DataSource, QueryFailedError } from 'typeorm'
import { Token } from '../entities/token.entity'
import { Account } from '../entities/account.entity'
import { tokenEntityToDto } from '../dto/token.dto'

@Controller('sudt')
export default class SudtController extends BaseController {
#explorerHost = process.env.EXPLORER_HOST || 'https://explorer.nervos.org'
constructor(private _dataSource: DataSource) {
super()
}

@Post('/send')
async send(
@Body() { from, to, amount, typeArgs }: { from: string[]; to: string; amount: HexString; typeArgs: Hash },
Expand Down Expand Up @@ -39,4 +49,58 @@ export default class SudtController extends BaseController {
)
return SudtResponse.ok(await Tx.toJsonString(result))
}

@Post('/token')
async createToken(@Body() req: CreateTokenRequest) {
let owner = await this._dataSource.getRepository(Account).findOneBy({ address: req.account })
if (!owner) {
owner = await this._dataSource
.getRepository(Account)
.save(this._dataSource.getRepository(Account).create({ address: req.account }))
}

try {
const token = await this._dataSource
.getRepository(Token)
.save(this._dataSource.getRepository(Token).create({ ...req, ownerId: owner.id }))
return new SudtResponse('201', { url: `${this.#explorerHost}/transaction/${token.typeId}` })
} catch (e) {
if (e instanceof QueryFailedError) {
switch (e.driverError.code) {
case 'ER_DUP_ENTRY':
return SudtResponse.err('409', { message: 'Token already exists' })
}
}

console.error(e)
}
}

@Put('/token')
async updateToken(@Body() req: CreateTokenRequest) {
const token = await this._dataSource.getRepository(Token).findOneBy({ typeId: req.typeId })
if (token) {
await this._dataSource.getRepository(Token).save({ ...token, ...req })
}

return new SudtResponse('201', {})
}

@Get('/token/:typeId')
async getToken(@Param('typeId') typeId: string) {
const token = await this._dataSource.getRepository(Token).findOneBy({ typeId })

if (token) {
return SudtResponse.ok(tokenEntityToDto(token, '0', this.#explorerHost))
} else {
throw new NotFound()
}
}

@Get('/tokens')
async listTokens() {
const tokens = await this._dataSource.getRepository(Token).find()

return SudtResponse.ok(tokens.map((token) => tokenEntityToDto(token, '0', this.#explorerHost)))
}
}
25 changes: 25 additions & 0 deletions packages/samples/sudt/src/dto/token.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Token } from '../entities/token.entity'

export interface TokenResponse {
symbol: string
name: string
amount: string
decimal: number
description: string
website: string
icon: string
explorerUrl: string
}

export const tokenEntityToDto = (token: Token, amount: string, explorerHost: string): TokenResponse => {
return {
symbol: token.name,
name: token.name,
amount,
decimal: token.decimal,
description: token.description ?? '',
website: token.website,
icon: token.icon,
explorerUrl: `${explorerHost}/sudt/${token.typeId}`,
}
}
43 changes: 43 additions & 0 deletions packages/samples/sudt/src/entities/token.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Column, CreateDateColumn, Entity, Index, PrimaryGeneratedColumn, Unique, UpdateDateColumn } from 'typeorm'

@Entity()
export class Token {
@PrimaryGeneratedColumn()
id!: number

@Column()
name!: string

@Column({ default: 18 })
decimal!: number

@Column()
description?: string

@Column({ default: '' })
website!: string

@Column({ default: '' })
icon!: string

@Column({ default: '' })
txHash?: string

@Column()
@Index()
ownerId!: number

@Column()
@Unique('uniq_type_id', ['typeId'])
typeId!: string

@Column()
@Unique('uniq_args', ['args'])
args!: string

@CreateDateColumn()
createdAt!: Date

@UpdateDateColumn()
updatedAt!: Date
}
Loading

0 comments on commit 632d792

Please sign in to comment.