Skip to main content

Ask! 装饰器

Ask! 提供了一组装饰器来实现智能合约,通过传递参数对象来配置装饰器的行为。装饰器主要分为两层,类装饰器和字段装饰器,字段装饰器必须正确匹配相应的类装饰器。当使用的装饰器不加参数时,可以省略小括号。

注意 以下的装饰器设计仅适用于当前版本,许多特性还未稳定,可能在未来有所变动。

@contract#

类装饰器

装饰的类会自动成为智能合约一个实例。其子字段支持 @constructor@message 装饰器装饰。一个AS文件 只能定义一个@contract 类。

@constructor#

字段装饰器

该装饰器用于@contract 的非静态public方法,该方法不允许返回值,即返回类型为void。装饰的方法作为该合约的一个初始化构造方法。一个合约至少需要定义一个@constructor方法。

@constructor方法是在合约实例化时可执行的。合约可以定义多个构造方法,允许合约的用户以多种不同的方式实例化合约。

合约构造方法的配置总是为 payable = truemutates = true

示例如下。

@contractclass Flipper {  private stored: Stored;
  constructor() {    this.stored = new Stored();  }
  @constructor  init(initFlag: bool): void {    this.stored.flag = initFlag;  }
  // ...}

@doc#

@doc 用于为metadata.json生成的信息提供文档。它可以为@contract/@event/@message/@constructor声明添加文档注释。

示例如下。

@contract@doc(desc = "MyToken conract that implement erc20 contract")class MyToken {  // ...}

@message#

字段装饰器

该装饰器用于 @contract的非静态public方法。装饰的方法作为合约的消息API供用户调用该合约。一个合约至少需要定义一个@constructor方法或者继承了其他合约。

@message方法是在合约执行的被调用的。合约可以定义多个消息方法。消息方法的返回值会返回给用户,因此需要实现Codec接口。如果您需要返回一些集合类型,那么需要使用Ask! 提供的一些实现 Codec 接口的集合类型。

合约消息方法默认配置为payable = falsemutates = true,当配置为true时,合约会在运行时做相应的检查。

  • payable 表示方法可以接受value。
  • mutates 表示方法是否能够改变存储变量的值。

示例如下。

@contractclass Flipper {  private stored: Stored;  constructor() {    this.stored = new Stored();  }
  @constructor  default(initFlag: bool): void {    this.stored.flag = initFlag;  }
  @message  flip(): void {    const v = this.stored.flag;    this.stored.flag = !v;  }
  @message(mutates = false)  get(): bool {    return this.stored.flag;  }}

@storage#

类装饰器

定义一个合约存储类,这个类应该只能作为@contract类的字段。

@event#

类装饰器

详情请参见Event

@topic#

字段装饰器

@topic 装饰的属性字段,会额外生成一个主题索引。每个事件的索引是有数量限制的(默认最大为4个)。

@dynamic#

类装饰器

@dynamic 装饰器用来装饰一个合约的APIs,这个合约已经存在于链上。通过在@dynamic类里声明链上的合约接口,Ask会自动生成相应的跨合约调用代码。

假设下面的合约A已经存在链上。

@contractclass Libadd {  constructor() {}
  @constructor  default(): void {}
  @message(mutates = false)  add(a: i32, b: i32): i32 {    return a + b;  }}

如果想在合约B里面想调用该合约,您可以声明一个@dynamic类来描述其接口。

@dynamicexport class Libadd {  // 注意这里的方法体会被实际的代码覆盖,这样写主要是为了通过编译  add(a: i32, b: i32): i32 {    return 0;  }}
@contractclass LibaddCaller {  constructor() {}
  @constructor  default(): void {}
  @message(mutates = false)  callAddFromExternal(outAddress: AccountId, a: i32, b: i32): i32 {    let outContract = new Libadd(outAddress);    let val = outContract.add(a, b);    return val;  }}

这里的outAddress是合约Libadd的实例地址。

该功能也可以调用其他智能合约语言编写的合约,例如ink!,只要遵循兼容的metadata.json规范。