This is copy from https://kusama.polkassembly.io/post/495 and external review from @shamb0 for v0.1 can be found at Review Form and Review Report
Patract had finished the development for Ask! v0.1 (funded by Treasury #66) and written a report #494. Ask!'s goal is to provide a set of contract framework and compilation tools using AssemblyScript (aka AS) as the programming language. Contracts written through Ask! can run in the FRAME Contracts Pallet, and eventually can call each other with contracts written by ink!.
This proposal will add the following new features on the basis of v0.1.
In the v0.1, we have implemented the basic data types i8
/u8
, i16
/u16
, i32
/u32
, i64
/u64
, string
, The save and load function of bool
, in the v0.2, we will support the save and load of map, array, object and other composite data types. In order to provide flexibility in data storage, but also for storage efficiency on certain scenarios, we will provide two storage methods: spread
and packed
.
@storage
is specified as a persistent storage class, and it is stored in the way of spread
by default, that is: the preprocessor will generate a key for each member in the storage class, and then use the hash of this key as the index , save the value of the member variable to the chain, and the saved data value is the original value of the member variable, without compression and other operations;packed
method is used to store a member (especially compound members, such as object, map, array) in a packed manner. If a member is designated as a packed member, its sub-members will not continue to expand, but to save and load as a whole. And it will be compressed when saving, and decompressed when loading. The members stored in packed
method need to be explicitly specified by the developer using the @packed
annotation.For the part of the composite type, the types commonly used in std
are basically implemented in ink!. As far as Ask! is concerned, this version provides a **complete infrastructure for composite types **, and implements the most commonly used composite types. Therefore, like ink!, the corresponding realization of multiple composite types needs to be gradually supplemented in future versions.
The basic functions of the four annotations @contract
, @storage
, @constructor
, and @message
have been implemented in the v0.1. In this proposal, their functions will be improved and @event
annotations will be introduced to support event functions.
@ignore
and @packed
for @storage
class.@ignore
annotation is used to indicate that a particular member variable does not need to be persistently stored. It only saves the set value during one call, and after the call is completed, it is destroyed from memory.@packed
annotation is used to indicate that a member variable is stored in a packed and compressed manner.payable
, mutates
, selector
for @message
annotation.payable
parameter is used to indicate whether the message can accept value. The default value is false
.mutates
parameter is used to indicate whether the message changes the value of the stored data. The default value is true
.selector
parameter is to specify the selector of the message, that is, if the name of the message is changed, its selector will also use the specified value.@event
and @topic
annotations to support event functions.@event
acts on the class, and the preprocessor will generate the emit
logic code for this class.@topic
acts on the member variables of the event class. The marked member variables will be written into the topic field.This function is mainly for the preprocessor to process the inheritance relationship between two classes annotated with @contract
. AS language itself supports class inheritance, so the main job of the preprocessor is to process @message
, @constructor
, @storage
, these three annotations related to the contract function. Due to class inheritance, the message and constructor methods will be overridden. At this time, the preprocessor determines the call of the call
entry function based on the actual contract writing assign logic, and generate the content of the corresponding field in metadata.json.
The function will follow the following principles:
@constructor
method is mainly based on subclasses. If it is not provided in the subclass, it is ignored. Because the parent class cannot know the member variables in the subclass, it cannot initialize the contract completely.@message
method uses the union of all messages in the parent class and the subclass. If an override occurs, the message in the subclass is the main one.@storage
is not encapsulated, the inheritance relationship is determined by the developer.ink! currently does not have the ability to inherit/reuse contracts, so Ask! has no reference samples, see issue: [https://github.com/paritytech/ink/issues/625](https://github.com /paritytech/ink/issues/625). In this version, Ask! will implement the corresponding grammatical features of AssemblyScript to simulate the effect of contract inheritance in Solidity.
Because there is no reference sample in this part, the time-consuming implementation may be biased, the completeness of the implementation cannot be clearly guaranteed, and there may be some edge problems that cannot be handled. In short, this part will be designed with reference to the implementation of Solidity. If this part can be implemented successfully, the Ask! contract has features that the ink! contract does not have, and this feature is of great significance to the prosperity of the contract ecosystem .
In the v0.1 version, we have supported the function of using Abi.ts for cross-contract calls, that is, using the following methods:
let data = Abi.encode("addFunc", [new UInt32(1), new UInt32(2)]);
let val = this.another.call(data);
However, this method is not conducive to code reuse and maintenance, so the @dynamic annotation is introduced to indicate that a class can be called across contracts.
The @dynamic
function is the cornerstone of the definition of contract standards, and is an indispensable function in the contract. Based on this function, the interface can be designed for the contract and the agreement can be made similar to ERC20.
@dynamic
acts on the class, the class marked as dynamic, the preprocessor will generate remote call logic for each of its methods, developers do not need to write implementation logic for the methods of the dynamic class. The use of dynamic will be as follows The code shows:
// define a class as dynamic
@dynamic
class IERC20 {
transfer(from: AccountId, to: AccountId, value: u128): void {}
}
// use dynamic class.
let ksm = new IERC20(new AccountId('0x12345678...'));
ksm.transfer(msg.sender, this.address, msg.value);
Here we don't use the interface
keyword, because the interface in AS cannot be a new instance, and the syntax cannot support such an operation.
The definition of @dynamic
is similar to the function of interface
in Solidity. ink! tries to use #[ink::trait_definition]
to implement this. The current design of this part is very imperfect, and a new design has been proposed recently. For details, please refer to the issue: [https://github.com/paritytech/ink/issues/631](https://github.com/ paritytech/ink/issues/631). On the other hand, we believe that the current implementation of ink! contains many problems, see issue:[https://github.com/paritytech/ink/issues/683](https://github.com/paritytech/ink/ issues/683).
Through the above discussion, it can be seen that this feature needs to be carefully designed and there are also various problems in the current ink! design. Therefore, this function may encounter unexpected problems in practice, so this part may also exceed the expected time in practice. Due to language features, we expect that the implementation of this part should be easier than the implementation of ink!.
On the other hand, we hope that the contracts written by Ask! and ink! can call each other. Therefore, in this version we will use this function to design simple cases, for example, manually write the corresponding @dynamic
annotated class for the content of the ink! contract, and test the mutual call. But if the ink! contract needs to be more smoothly combined with the Ask! contract, for example, to provide the function of parsing ink!’s metadata to automatically generate the corresponding @dynamic
modified class
, you need to pay a lot of extra work to design according tools. For example, combine this function with ask-cli
. These extra workloads are not included in the implementation of this version and will be arranged in subsequent versions.
In v0.1, we discussed with Parity team about the type generation part in the contract metadata. The type information of metadata is very useful for third-party applications. Currently, the scale-info
library is used in ink! as a library for generating contract type information. This library comes from:
@Robin from the parity team informed that the current scale-info is not mature enough to cover many possible situations, so it cannot be used in the Runtime of Substrate to help the Runtime generate type information in the Runtime (so the polkadot.js api needs developer to provide Extending types). And scale-info
is more closely bound to the rust
syntax, and in many cases it cannot be applied to the type of AS.
Therefore, for the type information part of the contract metadata, we plan to redesign a tool library for AS types and similar in function to scale-info
. Since this library is for AS, its corresponding third-party parsing part also needs to be implemented. Therefore, corresponding to this library, we need to add corresponding implementations in the SDKs of different languages:
Except for polkadot.js, the SDKs of other languages are controlled by Patract, so theoretically, we can finally achieve the type information analysis corresponding to Ask!.
However, the workload of implementing this library and the SDK of the corresponding language is huge and cumbersome. On the other hand, the export of type information does not affect the execution of the contract itself.
At the same time, scale-info
itself is not mature. ** Therefore, this part will not be planned to be implemented in this version (v0.2), but is planned to be in a later version. **
Week 1~3 (3 developers):
spread
and packed
storage solutions.Week 4~5 (3 developers):
@event
annotation, including the @event sub-annotation @topic
. Implement the event function in the contract.@storage
annotation.@ignore
: Ignored data members, marked data members will not be persisted.@packed
: Persistence in packed mode for array&map and other types. By default, persistence in spread mode is performed.@message
annotation:Supports annotations like @message(payable, mutates = false, selector='0x2345678')
.payable
: Indicates that the message accepts the transfer value, the default is not to accept.mutates
: Indicates whether the message changes the state variable. The default value is true
.selector
: Specify the selector of the message, no matter what the name of the message is, the specified selector is used.Week 6~7 (3 developers): Implement @dynamic
annotation function.
dynamic
annotation.dynamic
class method, function body implementation and return value processing logic.Week 8~10 (3 developers): Implement contract inheritance function.
call
method and metadata.json information.@constructor
method information on the inheritance link and hide the constructor methods in all parent classes.The sample contracts will contain the following:
spread
and packed
storage methods for composite data types like maps, arrays, and objects.@ignore
, @packed
, @event
, and @topic
to enhance contract functionality.@dynamic
annotation for easier cross-contract calls, enabling interoperability between contracts.@event
and @topic
annotations.