From 2e8fb14e727f8527617c84cc37faaeaa80e8ecd0 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Wed, 24 Nov 2021 17:14:01 +0800 Subject: [PATCH 01/27] Dapi for N3 --- nep-20.mediawiki | 374 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 nep-20.mediawiki diff --git a/nep-20.mediawiki b/nep-20.mediawiki new file mode 100644 index 00000000..533fba10 --- /dev/null +++ b/nep-20.mediawiki @@ -0,0 +1,374 @@ +
+  NEP: 20
+  Title: Dapi for N3
+  Author: Erik Zhang 
+  Type: Standard
+  Status: Accepted
+  Created: 2021-11-24
+
+ +==Abstract== + +This NEP describes a common API interface for dApps to communicate with external wallet providers. The use of a trusted 3rd party wallet providers will help users feel more secure when using dApps, and the unified interface will help dApp creators to have a more uniform developer experience when making their dApps compatible with various providers. + +==Motivation== + +===End Users=== + +As dApps come into the ecosystem, there will be more concerns about the safety of user assets. If dApps all required users to input their private keys in order to use them, it just takes one malicious dApp to steal all their funds. By using a trusted wallet provider which interfaces with the various dApps in the ecosystem on their behalf, users can reduce the exposure of their private keys. This will even allow users to transact with their hardware wallets via the wallet provider, never having to reveal their private keys even to the wallet itself. + +===dApp Developers=== + +One of the initial hurdles for any developer when starting to develop a dApp is to create a wallet module that will allow the user and application to interface with the NEO blockchain. While there are many quality SDKs out there, such as neon-js, for facilitating the communication of these requests, there are often many hurdles to successfully construct the right combination of methods, along with input and output parsing. The issue only gets amplified when trying to integrate with hardware wallet providers such as a Ledger device. + +While there may be several options for 3rd party wallet providers that will help them to facilitate these transactions, there is currently no common consensus on the consistency of their interfaces. With a lack of consistency in interfaces to use these wallet provider services, dApp developers will be forced to make a decision to have their platform supported by a single provider, or to double or even triple their development efforts to accommodate all the different wallet provider interfaces. This will lead to a fragmentation in the dApps ecosystem. + +===Wallet providers=== + +Each wallet provider, when deciding on supporting dApps to utilize their services as an authentication mechanism will be faced with a decision on how to implement an API to communicate with the dApps. Wallet providers can choose to create their own API from scratch, create their own version of existing projects, or aim to directly duplicate an existing API. In the case that the provider decides to make their own API interface from scratch, and try to promote dApps to use it, time and effort will inevitably be wasted by both the provider and competing providers on getting dApp developers on board with using their custom communication interface. If we have a unified interface for such transactions, providers could spend more time on making their individual services better for their users. + +==Specification== + +
+export type Base64Encoded = string;
+
+export type Address = string;
+
+export type UInt160 = string;
+
+export type UInt256 = string;
+
+export type ECPoint = string;
+
+export enum Network {
+    MAINNET = 860833102,
+    TESTNET = 877933390
+}
+
+export type ContractParameterType =
+    "Any" |
+    "Boolean" |
+    "Integer" |
+    "ByteArray" |
+    "String" |
+    "Hash160" |
+    "Hash256" |
+    "PublicKey" |
+    "Signature" |
+    "Array" |
+    "Map" |
+    "InteropInterface" |
+    "Void";
+
+export type Parameter = {
+    name?: string;
+    type: ContractParameterType;
+}
+
+export type Account = {
+    hash: UInt160;
+    label?: string;
+    isDefault: boolean;
+    contract?: {
+        script?: Base64Encoded;
+        parameters: Parameter[];
+        deployed: boolean;
+    };
+}
+
+export type WitnessScope =
+    "None" |
+    "CalledByEntry" |
+    "CustomContracts" |
+    "CustomGroups" |
+    "WitnessRules" |
+    "Global" |
+    "CalledByEntry, CustomContracts" |
+    "CalledByEntry, CustomGroups" |
+    "CalledByEntry, WitnessRules" |
+    "CustomContracts, CustomGroups" |
+    "CustomContracts, WitnessRules" |
+    "CustomGroups, WitnessRules" |
+    "CalledByEntry, CustomContracts, CustomGroups" |
+    "CalledByEntry, CustomContracts, WitnessRules" |
+    "CalledByEntry, CustomGroups, WitnessRules" |
+    "CustomContracts, CustomGroups, WitnessRules" |
+    "CalledByEntry, CustomContracts, CustomGroups, WitnessRules";
+
+export type WitnessConditionType =
+    "Boolean" |
+    "Not" |
+    "And" |
+    "Or" |
+    "ScriptHash" |
+    "Group" |
+    "CalledByEntry" |
+    "CalledByContract" |
+    "CalledByGroup";
+
+export interface WitnessCondition {
+    type: WitnessConditionType;
+}
+
+export interface BooleanCondition extends WitnessCondition {
+    type: "Boolean";
+    expression: boolean;
+}
+
+export interface NotCondition extends WitnessCondition {
+    type: "Not";
+    expression: WitnessCondition;
+}
+
+export interface AndCondition extends WitnessCondition {
+    type: "And";
+    expressions: WitnessCondition[];
+}
+
+export interface OrCondition extends WitnessCondition {
+    type: "Or";
+    expressions: WitnessCondition[];
+}
+
+export interface ScriptHashCondition extends WitnessCondition {
+    type: "ScriptHash";
+    hash: UInt160;
+}
+
+export interface GroupCondition extends WitnessCondition {
+    type: "Group";
+    group: ECPoint;
+}
+
+export interface CalledByEntryCondition extends WitnessCondition {
+    type: "CalledByEntry";
+}
+
+export interface CalledByContractCondition extends WitnessCondition {
+    type: "CalledByContract";
+    hash: UInt160;
+}
+
+export interface CalledByGroupCondition extends WitnessCondition {
+    type: "CalledByGroup";
+    group: ECPoint;
+}
+
+export type WitnessRule = {
+    action: "Deny" | "Allow";
+    condition: WitnessCondition;
+}
+
+export type Signer = {
+    account: UInt160;
+    scopes: WitnessScope;
+    allowedContracts?: UInt160[];
+    allowedGroups?: ECPoint[];
+    rules?: WitnessRule[];
+}
+
+export type TransactionAttributeType =
+    "HighPriority" |
+    "OracleResponse";
+
+export interface TransactionAttribute {
+    type: TransactionAttributeType;
+}
+
+export interface HighPriorityAttribute extends TransactionAttribute {
+    type: "HighPriority";
+}
+
+export type OracleResponseCode =
+    "Success" |
+    "ProtocolNotSupported" |
+    "ConsensusUnreachable" |
+    "NotFound" |
+    "Timeout" |
+    "Forbidden" |
+    "ResponseTooLarge" |
+    "InsufficientFunds" |
+    "ContentTypeNotSupported" |
+    "Error";
+
+export interface OracleResponse extends TransactionAttribute {
+    type: "OracleResponse";
+    id: bigint;
+    code: OracleResponseCode;
+    result?: Base64Encoded;
+}
+
+export type Transaction = {
+    hash: UInt256;
+    size: number;
+    blockHash: UInt256;
+    blockTime: bigint;
+    confirmations: number;
+    version: number;
+    nonce: number;
+    systemFee: bigint;
+    networkFee: bigint;
+    validUntilBlock: number;
+    sender: UInt160;
+    signers: Signer[];
+    attributes: TransactionAttribute[];
+    script: Base64Encoded;
+}
+
+export type Block = {
+    hash: UInt256;
+    size: number;
+    confirmations: number;
+    nextBlockHash?: UInt256;
+    version: number;
+    previousBlockHash: UInt256;
+    merkleRoot: UInt256;
+    time: bigint;
+    nonce: bigint;
+    index: number;
+    primary: number;
+    nextConsensus: UInt160;
+    tx: Transaction[];
+}
+
+export type TriggerType =
+    "OnPersist" |
+    "PostPersist" |
+    "Verification" |
+    "Application";
+
+export type VMState =
+    "NONE" |
+    "HALT" |
+    "FAULT" |
+    "BREAK";
+
+export type StackItemType =
+    "Any" |
+    "Pointer" |
+    "Boolean" |
+    "Integer" |
+    "ByteString" |
+    "Buffer" |
+    "Array" |
+    "Struct" |
+    "Map" |
+    "InteropInterface";
+
+export type Argument = {
+    type: StackItemType;
+    value?: any;
+}
+
+export type ApplicationLog = {
+    txid: UInt256;
+    executions: {
+        trigger: TriggerType;
+        vmstate: VMState;
+        exception?: string;
+        gasconsumed: bigint;
+        stack: Argument[];
+        notifications: Notification[];
+    }[];
+}
+
+export type Token = {
+    symbol: string;
+    decimals: number;
+    totalSupply: bigint;
+}
+
+export type InvokeResult = {
+    script: Base64Encoded;
+    state: VMState;
+    gasconsumed: bigint;
+    exception?: string;
+    stack: Argument[];
+}
+
+export type ContractParametersContext = {
+    type: "Neo.Network.P2P.Payloads.Transaction";
+    data: Base64Encoded;
+    items: Record;
+    }>;
+    network: Network;
+}
+
+export type AuthenticationChallengePayload = {
+    action: "Authentication";
+    grant_type: "Signature";
+    allowed_algorithms: ["ECDSA-P256"];
+    network: Network;
+    nonce: string;
+    timestamp: number;
+}
+
+export type AuthenticationResponsePayload = {
+    algorithm: "ECDSA-P256";
+    pubkey: ECPoint;
+    address: Address;
+    nonce: string;
+    timestamp: number;
+    signature: Base64Encoded;
+}
+
+export type ErrorType =
+    "UNSUPPORTED" |         // The requested feature or operation is not supported.
+    "INVALID" |             // The input data is in an invalid format.
+    "NOTFOUND" |            // The requested data doesn't exist.
+    "FAILED" |              // The contract execution failed.
+    "TIMEOUT" |             // The requested operation was cancelled due to timeout.
+    "CANCELED" |            // The requested operation was cancelled by the user.
+    "INSUFFICIENT_FUNDS" |  // The requested operation failed due to insufficient balance.
+    "RPC_ERROR" |           // An exception was thrown by the RPC server.
+    "UNKNOWN";              // An unknown error has occurred.
+
+export type Error = { // All possible reasons returned by the onrejected callback of promises.
+    type: ErrorType;
+    message: string;
+}
+
+export interface IDapiProvider {
+    // Properties
+    compatibility: string[];
+    extra: any;
+    name: string;
+    network: Network;
+    supportedNetworks: Network[];
+    version: string;
+    website: string;
+
+    // Events
+    on(event: "accountschanged", listener: () => void): void;
+    on(event: "networkchanged", listener: () => void): void;
+    on(event: "ready", listener: (provider: IDapiProvider) => void): void; // When the event is triggered, it also triggers the "Neo.DapiProvider.ready" event of the window object.
+
+    // Methods
+    authentication(payload: AuthenticationChallengePayload): Promise;
+    call(hash: UInt160, operation: string, args: Argument[], signers: Signer[]): Promise;
+    getAccounts(): Promise;
+    getApplicationLog(txid: UInt256): Promise;
+    getBalance(asset: UInt160, account?: UInt160): Promise;
+    getBlock(hash: UInt256): Promise;
+    getBlock(index: number): Promise;
+    getBlockCount(): Promise;
+    getStorage(hash: UInt160, key: Base64Encoded): Promise;
+    getTokenInfo(hash: UInt160): Promise;
+    getTransaction(txid: UInt256): Promise;
+    invoke(hash: UInt160, operation: string, args: Argument[], signers: Signer[]): Promise;
+    send(asset: UInt160, amount: bigint, to: UInt160, from?: UInt160): Promise;
+    sign(context: ContractParametersContext): Promise;
+}
+
+ +==Rationale== + +This protocol will allow dApp developers to create applications that interact with the NEO blockchain without having to be concerned about managing a full wallet within their application or the details related to handing transaction creation or broadcasting. This will also allow dApps to allow users to transact in a secure fashion that does not require sharing of their private key. + +==Implementation== From 62394aed4053dfde5d5572bb91460a6b0200e33e Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 19:14:06 +0800 Subject: [PATCH 02/27] Avoid bigint --- nep-20.mediawiki | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 533fba10..1a46b31f 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -40,6 +40,10 @@ export type UInt256 = string; export type ECPoint = string; +export type Integer = string; + +export type HexString = string; + export enum Network { MAINNET = 860833102, TESTNET = 877933390 @@ -193,7 +197,7 @@ export type OracleResponseCode = export interface OracleResponse extends TransactionAttribute { type: "OracleResponse"; - id: bigint; + id: number; code: OracleResponseCode; result?: Base64Encoded; } @@ -202,12 +206,12 @@ export type Transaction = { hash: UInt256; size: number; blockHash: UInt256; - blockTime: bigint; + blockTime: number; confirmations: number; version: number; nonce: number; - systemFee: bigint; - networkFee: bigint; + systemFee: Integer; + networkFee: Integer; validUntilBlock: number; sender: UInt160; signers: Signer[]; @@ -223,8 +227,8 @@ export type Block = { version: number; previousBlockHash: UInt256; merkleRoot: UInt256; - time: bigint; - nonce: bigint; + time: number; + nonce: HexString; index: number; primary: number; nextConsensus: UInt160; @@ -266,7 +270,7 @@ export type ApplicationLog = { trigger: TriggerType; vmstate: VMState; exception?: string; - gasconsumed: bigint; + gasconsumed: Integer; stack: Argument[]; notifications: Notification[]; }[]; @@ -275,13 +279,13 @@ export type ApplicationLog = { export type Token = { symbol: string; decimals: number; - totalSupply: bigint; + totalSupply: Integer; } export type InvokeResult = { script: Base64Encoded; state: VMState; - gasconsumed: bigint; + gasconsumed: Integer; exception?: string; stack: Argument[]; } @@ -354,7 +358,7 @@ export interface IDapiProvider { call(hash: UInt160, operation: string, args: Argument[], signers: Signer[]): Promise; getAccounts(): Promise; getApplicationLog(txid: UInt256): Promise; - getBalance(asset: UInt160, account?: UInt160): Promise; + getBalance(asset: UInt160, account?: UInt160): Promise; getBlock(hash: UInt256): Promise; getBlock(index: number): Promise; getBlockCount(): Promise; @@ -362,7 +366,7 @@ export interface IDapiProvider { getTokenInfo(hash: UInt160): Promise; getTransaction(txid: UInt256): Promise; invoke(hash: UInt160, operation: string, args: Argument[], signers: Signer[]): Promise; - send(asset: UInt160, amount: bigint, to: UInt160, from?: UInt160): Promise; + send(asset: UInt160, amount: Integer, to: UInt160, from?: UInt160): Promise; sign(context: ContractParametersContext): Promise; } From 9459556eee22f62773ca718a5d2125dd0d18cc05 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 19:19:09 +0800 Subject: [PATCH 03/27] Rename --- nep-20.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 1a46b31f..2df94097 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -354,7 +354,7 @@ export interface IDapiProvider { on(event: "ready", listener: (provider: IDapiProvider) => void): void; // When the event is triggered, it also triggers the "Neo.DapiProvider.ready" event of the window object. // Methods - authentication(payload: AuthenticationChallengePayload): Promise; + authenticate(payload: AuthenticationChallengePayload): Promise; call(hash: UInt160, operation: string, args: Argument[], signers: Signer[]): Promise; getAccounts(): Promise; getApplicationLog(txid: UInt256): Promise; From cb8cdce495b998d7d530b0d5d3895a1ba60e8408 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 19:27:00 +0800 Subject: [PATCH 04/27] Add `details` to `Error` type --- nep-20.mediawiki | 1 + 1 file changed, 1 insertion(+) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 2df94097..b4506e7e 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -336,6 +336,7 @@ export type ErrorType = export type Error = { // All possible reasons returned by the onrejected callback of promises. type: ErrorType; message: string; + details?: any; } export interface IDapiProvider { From 9740597fb82fd61a71e098220e029c4585ebbe80 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 19:34:52 +0800 Subject: [PATCH 05/27] Split into paragraphs --- nep-20.mediawiki | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index b4506e7e..8f3272d1 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -29,6 +29,8 @@ Each wallet provider, when deciding on supporting dApps to utilize their service ==Specification== +===Types=== +
 export type Base64Encoded = string;
 
@@ -321,24 +323,11 @@ export type AuthenticationResponsePayload = {
     timestamp: number;
     signature: Base64Encoded;
 }
+
-export type ErrorType = - "UNSUPPORTED" | // The requested feature or operation is not supported. - "INVALID" | // The input data is in an invalid format. - "NOTFOUND" | // The requested data doesn't exist. - "FAILED" | // The contract execution failed. - "TIMEOUT" | // The requested operation was cancelled due to timeout. - "CANCELED" | // The requested operation was cancelled by the user. - "INSUFFICIENT_FUNDS" | // The requested operation failed due to insufficient balance. - "RPC_ERROR" | // An exception was thrown by the RPC server. - "UNKNOWN"; // An unknown error has occurred. - -export type Error = { // All possible reasons returned by the onrejected callback of promises. - type: ErrorType; - message: string; - details?: any; -} +===Interfaces=== +
 export interface IDapiProvider {
     // Properties
     compatibility: string[];
@@ -372,6 +361,27 @@ export interface IDapiProvider {
 }
 
+===Errors=== + +
+export type ErrorType =
+    "UNSUPPORTED" |         // The requested feature or operation is not supported.
+    "INVALID" |             // The input data is in an invalid format.
+    "NOTFOUND" |            // The requested data doesn't exist.
+    "FAILED" |              // The contract execution failed.
+    "TIMEOUT" |             // The requested operation was cancelled due to timeout.
+    "CANCELED" |            // The requested operation was cancelled by the user.
+    "INSUFFICIENT_FUNDS" |  // The requested operation failed due to insufficient balance.
+    "RPC_ERROR" |           // An exception was thrown by the RPC server.
+    "UNKNOWN";              // An unknown error has occurred.
+
+export type Error = { // All possible reasons returned by the onrejected callback of promises.
+    type: ErrorType;
+    message: string;
+    details?: any;
+}
+
+ ==Rationale== This protocol will allow dApp developers to create applications that interact with the NEO blockchain without having to be concerned about managing a full wallet within their application or the details related to handing transaction creation or broadcasting. This will also allow dApps to allow users to transact in a secure fashion that does not require sharing of their private key. From 5280cc9447d1ef055a238c3577febe27166bc0f4 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 20:32:08 +0800 Subject: [PATCH 06/27] Add "How to obtain an instance of IDapiProvider interface" --- nep-20.mediawiki | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 8f3272d1..e202e777 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -341,7 +341,6 @@ export interface IDapiProvider { // Events on(event: "accountschanged", listener: () => void): void; on(event: "networkchanged", listener: () => void): void; - on(event: "ready", listener: (provider: IDapiProvider) => void): void; // When the event is triggered, it also triggers the "Neo.DapiProvider.ready" event of the window object. // Methods authenticate(payload: AuthenticationChallengePayload): Promise; @@ -382,6 +381,18 @@ export type Error = { // All possible reasons returned by the onrejected callbac } +===How to obtain an instance of IDapiProvider interface?=== + +In order for dapps to have a unified method of obtaining IDapiProvider instances, all providers must trigger the Neo.DapiProvider.ready event of the window object when they are ready. + +The front end of the dapp can listen to the event and obtain the IDapiProvider instance from the detail property of the event. + +
+window.addEventListener("Neo.DapiProvider.ready", e => {
+    var provider = e.detail.provider;
+});
+
+ ==Rationale== This protocol will allow dApp developers to create applications that interact with the NEO blockchain without having to be concerned about managing a full wallet within their application or the details related to handing transaction creation or broadcasting. This will also allow dApps to allow users to transact in a secure fashion that does not require sharing of their private key. From f7c5e162d4ea4965d99fcf01fff69093818f79f9 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 20:50:06 +0800 Subject: [PATCH 07/27] Improve invoke --- nep-20.mediawiki | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index e202e777..70c325e0 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -284,7 +284,15 @@ export type Token = { totalSupply: Integer; } -export type InvokeResult = { +export type InvocationArguments = { + hash: UInt160; + operation: string; + args: Argument[]; + signers?: Signer[]; + suggestedSystemFee?: Integer; +} + +export type InvocationResult = { script: Base64Encoded; state: VMState; gasconsumed: Integer; @@ -344,7 +352,7 @@ export interface IDapiProvider { // Methods authenticate(payload: AuthenticationChallengePayload): Promise; - call(hash: UInt160, operation: string, args: Argument[], signers: Signer[]): Promise; + call(hash: UInt160, operation: string, ...args: Argument[]): Promise; getAccounts(): Promise; getApplicationLog(txid: UInt256): Promise; getBalance(asset: UInt160, account?: UInt160): Promise; @@ -354,7 +362,7 @@ export interface IDapiProvider { getStorage(hash: UInt160, key: Base64Encoded): Promise; getTokenInfo(hash: UInt160): Promise; getTransaction(txid: UInt256): Promise; - invoke(hash: UInt160, operation: string, args: Argument[], signers: Signer[]): Promise; + invoke(invocations: InvocationArguments[]): Promise; send(asset: UInt160, amount: Integer, to: UInt160, from?: UInt160): Promise; sign(context: ContractParametersContext): Promise; } From e8dcf11aab4db2963da1e6a8333553a3ba22ca9d Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 21:06:34 +0800 Subject: [PATCH 08/27] Add makeTransaction and relay --- nep-20.mediawiki | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 70c325e0..f18ed943 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -302,6 +302,7 @@ export type InvocationResult = { export type ContractParametersContext = { type: "Neo.Network.P2P.Payloads.Transaction"; + hash: UInt256; data: Base64Encoded; items: Record; getTransaction(txid: UInt256): Promise; invoke(invocations: InvocationArguments[]): Promise; + makeTransaction(invocations: InvocationArguments[]): Promise; + relay(context: ContractParametersContext): Promise; send(asset: UInt160, amount: Integer, to: UInt160, from?: UInt160): Promise; sign(context: ContractParametersContext): Promise; } From 460fb0c3e94977e7e582a2889314c0a91e040662 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 21:30:42 +0800 Subject: [PATCH 09/27] Add FailedError --- nep-20.mediawiki | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index f18ed943..a65636ae 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -385,10 +385,15 @@ export type ErrorType = "RPC_ERROR" | // An exception was thrown by the RPC server. "UNKNOWN"; // An unknown error has occurred. -export type Error = { // All possible reasons returned by the onrejected callback of promises. +export interface Error { type: ErrorType; message: string; - details?: any; + detail?: any; +} + +export interface FailedError extends Error { + type: "FAILED"; + detail: InvocationResult; } From 84fe9225e72d2be2d87cbb9a3098249a5057e0b7 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Nov 2021 21:40:23 +0800 Subject: [PATCH 10/27] Add removeListener --- nep-20.mediawiki | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index a65636ae..44b16ad7 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -51,6 +51,10 @@ export enum Network { TESTNET = 877933390 } +export type EventName = + "accountschanged" | + "networkchanged"; + export type ContractParameterType = "Any" | "Boolean" | @@ -348,8 +352,8 @@ export interface IDapiProvider { website: string; // Events - on(event: "accountschanged", listener: () => void): void; - on(event: "networkchanged", listener: () => void): void; + on(event: EventName, listener: () => void): void; + removeListener(event: EventName, listener: () => void): void; // Methods authenticate(payload: AuthenticationChallengePayload): Promise; From fa93ca57627d9fb3b695c70acb62ba6e66507a0e Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 27 Nov 2021 08:35:54 +0800 Subject: [PATCH 11/27] Modify InvocationArguments --- nep-20.mediawiki | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 44b16ad7..de959753 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -292,8 +292,6 @@ export type InvocationArguments = { hash: UInt160; operation: string; args: Argument[]; - signers?: Signer[]; - suggestedSystemFee?: Integer; } export type InvocationResult = { @@ -357,6 +355,7 @@ export interface IDapiProvider { // Methods authenticate(payload: AuthenticationChallengePayload): Promise; + call(invocation: InvocationArguments): Promise; call(hash: UInt160, operation: string, ...args: Argument[]): Promise; getAccounts(): Promise; getApplicationLog(txid: UInt256): Promise; @@ -367,8 +366,8 @@ export interface IDapiProvider { getStorage(hash: UInt160, key: Base64Encoded): Promise; getTokenInfo(hash: UInt160): Promise; getTransaction(txid: UInt256): Promise; - invoke(invocations: InvocationArguments[]): Promise; - makeTransaction(invocations: InvocationArguments[]): Promise; + invoke(invocations: InvocationArguments[], signers?: Signer[], suggestedSystemFee?: Integer): Promise; + makeTransaction(invocations: InvocationArguments[], signers?: Signer[], suggestedSystemFee?: Integer): Promise; relay(context: ContractParametersContext): Promise; send(asset: UInt160, amount: Integer, to: UInt160, from?: UInt160): Promise; sign(context: ContractParametersContext): Promise; From 95a2db978138a9cd10e6590053f0f42565693e67 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Wed, 1 Dec 2021 14:08:30 +0800 Subject: [PATCH 12/27] Remove an overload of call --- nep-20.mediawiki | 1 - 1 file changed, 1 deletion(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index de959753..7674e3d8 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -356,7 +356,6 @@ export interface IDapiProvider { // Methods authenticate(payload: AuthenticationChallengePayload): Promise; call(invocation: InvocationArguments): Promise; - call(hash: UInt160, operation: string, ...args: Argument[]): Promise; getAccounts(): Promise; getApplicationLog(txid: UInt256): Promise; getBalance(asset: UInt160, account?: UInt160): Promise; From 6bdd0e041348c78407c766779167e7b056285ced Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Wed, 1 Dec 2021 14:17:24 +0800 Subject: [PATCH 13/27] Add dispatchEvent --- nep-20.mediawiki | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 7674e3d8..26c93a98 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -403,6 +403,14 @@ export interface FailedError extends Error { In order for dapps to have a unified method of obtaining IDapiProvider instances, all providers must trigger the Neo.DapiProvider.ready event of the window object when they are ready. +
+window.dispatchEvent(new CustomEvent("build", {
+    detail: {
+        provider: provider
+    }
+}));
+
+ The front end of the dapp can listen to the event and obtain the IDapiProvider instance from the detail property of the event.

From 89d6acc45b63312c46d32dd026f80bc21f0d35b1 Mon Sep 17 00:00:00 2001
From: Erik Zhang 
Date: Wed, 1 Dec 2021 14:21:51 +0800
Subject: [PATCH 14/27] fix

---
 nep-20.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/nep-20.mediawiki b/nep-20.mediawiki
index 26c93a98..bd1125f9 100644
--- a/nep-20.mediawiki
+++ b/nep-20.mediawiki
@@ -404,7 +404,7 @@ export interface FailedError extends Error {
 In order for dapps to have a unified method of obtaining IDapiProvider instances, all providers must trigger the Neo.DapiProvider.ready event of the window object when they are ready.
 
 
-window.dispatchEvent(new CustomEvent("build", {
+window.dispatchEvent(new CustomEvent("Neo.DapiProvider.ready", {
     detail: {
         provider: provider
     }

From 0e1ec0f9e556ee3781bc1cbeff696d39ce9fdc7a Mon Sep 17 00:00:00 2001
From: Erik Zhang 
Date: Wed, 1 Dec 2021 19:30:51 +0800
Subject: [PATCH 15/27] Add comments

---
 nep-20.mediawiki | 173 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 125 insertions(+), 48 deletions(-)

diff --git a/nep-20.mediawiki b/nep-20.mediawiki
index bd1125f9..6d5d8082 100644
--- a/nep-20.mediawiki
+++ b/nep-20.mediawiki
@@ -32,67 +32,84 @@ Each wallet provider, when deciding on supporting dApps to utilize their service
 ===Types===
 
 
+// Represents a piece of data encoded as a base64 string.
 export type Base64Encoded = string;
 
+// Represents a N3 address.
+// Example: "NSiVJYZej4XsxG5CUpdwn7VRQk8iiiDMPM"
 export type Address = string;
 
+// A 160-bit hash represented by a hexadecimal string.
+// Example: "0x682cca3ebdc66210e5847d7f8115846586079d4a"
 export type UInt160 = string;
 
+// A 256-bit hash represented by a hexadecimal string.
+// Example: "0x1f4d1defa46faa5e7b9b8d3f79a06bec777d7c26c4aa5f6f5899a291daa87c15"
 export type UInt256 = string;
 
+// Represents an ECC public key.
+// Example: "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"
 export type ECPoint = string;
 
+// A large integer of any length expressed as a string.
 export type Integer = string;
 
+// Represents a piece of data encoded as a hexadecimal string.
 export type HexString = string;
 
+// An enumeration representing the N3 network.
 export enum Network {
-    MAINNET = 860833102,
-    TESTNET = 877933390
+    MAINNET = 860833102, // Represents the N3 main network.
+    TESTNET = 877933390  // Represents the N3 test network.
 }
 
+// Represents the name of the event in IDapiProvider.
 export type EventName =
-    "accountschanged" |
-    "networkchanged";
+    "accountschanged" | // Triggered when the accounts in the wallet change.
+    "networkchanged";   // Triggered when the user switches the current network.
 
+// Represents the type of ContractParameter.
 export type ContractParameterType =
-    "Any" |
-    "Boolean" |
-    "Integer" |
-    "ByteArray" |
-    "String" |
-    "Hash160" |
-    "Hash256" |
-    "PublicKey" |
-    "Signature" |
-    "Array" |
-    "Map" |
-    "InteropInterface" |
-    "Void";
-
-export type Parameter = {
-    name?: string;
-    type: ContractParameterType;
+    "Any" |              // Indicates that the parameter can be of any type.
+    "Boolean" |          // Indicates that the parameter is of Boolean type.
+    "Integer" |          // Indicates that the parameter is an integer.
+    "ByteArray" |        // Indicates that the parameter is a byte array.
+    "String" |           // Indicates that the parameter is a string.
+    "Hash160" |          // Indicates that the parameter is a 160-bit hash.
+    "Hash256" |          // Indicates that the parameter is a 256-bit hash.
+    "PublicKey" |        // Indicates that the parameter is a public key.
+    "Signature" |        // Indicates that the parameter is a signature.
+    "Array" |            // Indicates that the parameter is an array.
+    "Map" |              // Indicates that the parameter is a map.
+    "InteropInterface" | // Indicates that the parameter is an interoperable interface.
+    "Void";              // It can be only used as the return type of a method, meaning that the method has no return value.
+
+// Represents a parameter of a contract method.
+export type ContractParameter = {
+    name?: string;               // The name of the parameter.
+    type: ContractParameterType; // The type of the parameter.
 }
 
+// Represents an account in a wallet.
 export type Account = {
-    hash: UInt160;
-    label?: string;
-    isDefault: boolean;
-    contract?: {
-        script?: Base64Encoded;
-        parameters: Parameter[];
-        deployed: boolean;
+    hash: UInt160;      // The script hash of the account.
+    label?: string;     // The label of the account.
+    isDefault: boolean; // Indicates whether the account is the default account.
+    contract?: {        // The contract of the account.
+        script?: Base64Encoded;          // The verification script of the contract.
+        parameters: ContractParameter[]; // The parameters of the verification script.
+        deployed: boolean;               // Indicates whether the contract is deployed on the blockchain.
     };
 }
 
+// Represents the scope of a witness.
 export type WitnessScope =
-    "None" |
-    "CalledByEntry" |
-    "CustomContracts" |
-    "CustomGroups" |
-    "WitnessRules" |
-    "Global" |
+    "None" |            // Indicates that no contract was witnessed. Only sign the transaction.
+    "CalledByEntry" |   // Indicates that the calling contract must be the entry contract.
+    "CustomContracts" | // Custom hash for contract-specific.
+    "CustomGroups" |    // Custom pubkey for group members.
+    "WitnessRules" |    // Indicates that the current context must satisfy the specified rules.
+    "Global" |          // This allows the witness in all contexts (default Neo2 behavior).
     "CalledByEntry, CustomContracts" |
     "CalledByEntry, CustomGroups" |
     "CalledByEntry, WitnessRules" |
@@ -105,19 +122,21 @@ export type WitnessScope =
     "CustomContracts, CustomGroups, WitnessRules" |
     "CalledByEntry, CustomContracts, CustomGroups, WitnessRules";
 
+// Represents the type of WitnessCondition.
 export type WitnessConditionType =
-    "Boolean" |
-    "Not" |
-    "And" |
-    "Or" |
-    "ScriptHash" |
-    "Group" |
-    "CalledByEntry" |
-    "CalledByContract" |
-    "CalledByGroup";
-
+    "Boolean" |          // Indicates that the condition will always be met or not met.
+    "Not" |              // Reverse another condition.
+    "And" |              // Indicates that all conditions must be met.
+    "Or" |               // Indicates that any of the conditions meets.
+    "ScriptHash" |       // Indicates that the condition is met when the current context has the specified script hash.
+    "Group" |            // Indicates that the condition is met when the current context has the specified group.
+    "CalledByEntry" |    // Indicates that the condition is met when the current context is the entry point or is called by the entry point.
+    "CalledByContract" | // Indicates that the condition is met when the current context is called by the specified contract.
+    "CalledByGroup";     // Indicates that the condition is met when the current context is called by the specified group.
+
+// Represents the condition of a WitnessRule.
 export interface WitnessCondition {
-    type: WitnessConditionType;
+    type: WitnessConditionType; // The type of the condition.
 }
 
 export interface BooleanCondition extends WitnessCondition {
@@ -340,42 +359,99 @@ export type AuthenticationResponsePayload = {
 
 
 export interface IDapiProvider {
+
     // Properties
+
+    // Indicates the standards supported by this provider.
+    // Example: ["NEP-11", "NEP-17"]
     compatibility: string[];
+
+    // Additional data for the provider.
     extra: any;
+
+    // The name of the provider.
     name: string;
+
+    // Indicates the network currently in use.
     network: Network;
+
+    // Indicates the networks supported by this provider.
     supportedNetworks: Network[];
+
+    // The version of the provider.
+    // Example: "1.0.0"
     version: string;
+
+    // The website of the provider.
     website: string;
 
+
     // Events
+
+    // Adds an event handler for the specified event.
     on(event: EventName, listener: () => void): void;
+
+    // Removes an event handler for the specified event.
     removeListener(event: EventName, listener: () => void): void;
 
+
     // Methods
+
+    // Requests for authentication. Usually used to log in to a website.
     authenticate(payload: AuthenticationChallengePayload): Promise;
+
+    // Calls a contract offchain and get the execution result.
     call(invocation: InvocationArguments): Promise;
+
+    // Gets all accounts in the current wallet.
     getAccounts(): Promise;
+
+    // Gets the application log of the specified transaction.
     getApplicationLog(txid: UInt256): Promise;
+
+    // Gets the balance of the specified account. If `account` is omitted, the sum of all account balances in the current wallet should be returned.
     getBalance(asset: UInt160, account?: UInt160): Promise;
+
+    // Gets the block of the specified hash.
     getBlock(hash: UInt256): Promise;
+
+    // Gets the block of the specified index.
     getBlock(index: number): Promise;
+
+    // Gets the count of blocks in the blockchain.
     getBlockCount(): Promise;
+
+    // Gets the specified storage entry.
     getStorage(hash: UInt160, key: Base64Encoded): Promise;
+
+    // Gets the information of the specified token.
     getTokenInfo(hash: UInt160): Promise;
+
+    // Gets the transaction of the specified hash.
     getTransaction(txid: UInt256): Promise;
+
+    // Calls one or more contracts onchain and returns the hash of the transaction.
     invoke(invocations: InvocationArguments[], signers?: Signer[], suggestedSystemFee?: Integer): Promise;
+
+    // Calls one or more contracts onchain and return the transaction without relaying.
     makeTransaction(invocations: InvocationArguments[], signers?: Signer[], suggestedSystemFee?: Integer): Promise;
+    
+    // Relays a transaction and returns the hash of it.
     relay(context: ContractParametersContext): Promise;
+
+    // Sends assets to an account and returns the hash of the transaction. If `from` is omitted, the wallet should automatically select an account or prompt the user to select one.
     send(asset: UInt160, amount: Integer, to: UInt160, from?: UInt160): Promise;
+
+    // Signs the transaction with the current wallet. Usually used for multi-signature transactions.
     sign(context: ContractParametersContext): Promise;
+
 }
 
===Errors===
+// The type of the Error.
 export type ErrorType =
     "UNSUPPORTED" |         // The requested feature or operation is not supported.
     "INVALID" |             // The input data is in an invalid format.
@@ -387,10 +463,11 @@ export type ErrorType =
     "RPC_ERROR" |           // An exception was thrown by the RPC server.
     "UNKNOWN";              // An unknown error has occurred.
 
+// The reason passed to the `onRejected` callback of the promises.
 export interface Error {
-    type: ErrorType;
-    message: string;
-    detail?: any;
+    type: ErrorType; // The type of the error.
+    message: string; // The message of the error.
+    detail?: any;    // Additional data for the error.
 }
 
 export interface FailedError extends Error {

From 21887fcfddfcbcae8454325ac80d3ef15f0de094 Mon Sep 17 00:00:00 2001
From: Erik Zhang 
Date: Sat, 4 Dec 2021 10:22:17 +0800
Subject: [PATCH 16/27] Allow private network

---
 nep-20.mediawiki | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/nep-20.mediawiki b/nep-20.mediawiki
index 6d5d8082..0c9bb507 100644
--- a/nep-20.mediawiki
+++ b/nep-20.mediawiki
@@ -57,11 +57,10 @@ export type Integer = string;
 // Represents a piece of data encoded as a hexadecimal string.
 export type HexString = string;
 
-// An enumeration representing the N3 network.
-export enum Network {
-    MAINNET = 860833102, // Represents the N3 main network.
-    TESTNET = 877933390  // Represents the N3 test network.
-}
+// Represents the N3 network.
+// MAINNET: 860833102
+// TESTNET: 877933390
+export type Network = number;
 
 // Represents the name of the event in IDapiProvider.
 export type EventName =

From 5165ead3a83954e13072d7f54b6956684af10241 Mon Sep 17 00:00:00 2001
From: Erik Zhang 
Date: Sat, 4 Dec 2021 10:32:56 +0800
Subject: [PATCH 17/27] Add abortOnFail to InvocationArguments

---
 nep-20.mediawiki | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/nep-20.mediawiki b/nep-20.mediawiki
index 0c9bb507..bbb2912c 100644
--- a/nep-20.mediawiki
+++ b/nep-20.mediawiki
@@ -306,10 +306,12 @@ export type Token = {
     totalSupply: Integer;
 }
 
+// Provides the necessary arguments for a contract call.
 export type InvocationArguments = {
-    hash: UInt160;
-    operation: string;
-    args: Argument[];
+    hash: UInt160;         // The hash of the contract to be called.
+    operation: string;     // The operation of the contract to be called.
+    args?: Argument[];     // The arguments for the call.
+    abortOnFail?: boolean; // Indicates whether the entire transaction should fail when the contract returns `false`.
 }
 
 export type InvocationResult = {

From 9f3a1df43c5630549dffebc039c392267ba76895 Mon Sep 17 00:00:00 2001
From: Erik Zhang 
Date: Sat, 4 Dec 2021 10:42:25 +0800
Subject: [PATCH 18/27] Add dapiVersion

---
 nep-20.mediawiki | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/nep-20.mediawiki b/nep-20.mediawiki
index bbb2912c..96e25df2 100644
--- a/nep-20.mediawiki
+++ b/nep-20.mediawiki
@@ -57,6 +57,10 @@ export type Integer = string;
 // Represents a piece of data encoded as a hexadecimal string.
 export type HexString = string;
 
+// Represents a version.
+// Example: "1.0.0"
+export type Version = string;
+
 // Represents the N3 network.
 // MAINNET: 860833102
 // TESTNET: 877933390
@@ -366,6 +370,9 @@ export interface IDapiProvider {
     // Indicates the standards supported by this provider.
     // Example: ["NEP-11", "NEP-17"]
     compatibility: string[];
+    
+    // The version of the Dapi. It must currently be "1.0".
+    dapiVersion: Version;
 
     // Additional data for the provider.
     extra: any;
@@ -380,8 +387,7 @@ export interface IDapiProvider {
     supportedNetworks: Network[];
 
     // The version of the provider.
-    // Example: "1.0.0"
-    version: string;
+    version: Version;
 
     // The website of the provider.
     website: string;

From 6f73dd513fcc8cb01e6d12a899c1376a53baf783 Mon Sep 17 00:00:00 2001
From: Erik Zhang 
Date: Sat, 4 Dec 2021 10:57:36 +0800
Subject: [PATCH 19/27] Add signMessage

---
 nep-20.mediawiki | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/nep-20.mediawiki b/nep-20.mediawiki
index 96e25df2..9010706f 100644
--- a/nep-20.mediawiki
+++ b/nep-20.mediawiki
@@ -416,7 +416,8 @@ export interface IDapiProvider {
     // Gets the application log of the specified transaction.
     getApplicationLog(txid: UInt256): Promise;
 
-    // Gets the balance of the specified account. If `account` is omitted, the sum of all account balances in the current wallet should be returned.
+    // Gets the balance of the specified account.
+    // If `account` is omitted, the sum of all account balances in the current wallet should be returned.
     getBalance(asset: UInt160, account?: UInt160): Promise;
 
     // Gets the block of the specified hash.
@@ -446,11 +447,17 @@ export interface IDapiProvider {
     // Relays a transaction and returns the hash of it.
     relay(context: ContractParametersContext): Promise;
 
-    // Sends assets to an account and returns the hash of the transaction. If `from` is omitted, the wallet should automatically select an account or prompt the user to select one.
+    // Sends assets to an account and returns the hash of the transaction.
+    // If `from` is omitted, the wallet should automatically select an account or prompt the user to select one.
     send(asset: UInt160, amount: Integer, to: UInt160, from?: UInt160): Promise;
 
     // Signs the transaction with the current wallet. Usually used for multi-signature transactions.
     sign(context: ContractParametersContext): Promise;
+    
+    // Signs the message with the specified account.
+    // If `salt` is omitted, no salt will be used.
+    // If `account` is omitted, the wallet should automatically select an account or prompt the user to select one.
+    signMessage(message: Base64Encoded, salt?: Base64Encoded, account?: UInt160);
 
 }
 
From 54f2603d258951c4b9787097d5d9e207b8eeb3f2 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 4 Dec 2021 11:05:56 +0800 Subject: [PATCH 20/27] Fix signMessage --- nep-20.mediawiki | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 9010706f..b3752f8c 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -455,9 +455,10 @@ export interface IDapiProvider { sign(context: ContractParametersContext): Promise; // Signs the message with the specified account. + // The algorithm used is ECDsa with SHA256. // If `salt` is omitted, no salt will be used. // If `account` is omitted, the wallet should automatically select an account or prompt the user to select one. - signMessage(message: Base64Encoded, salt?: Base64Encoded, account?: UInt160); + signMessage(message: Base64Encoded, salt?: Base64Encoded, account?: UInt160): Base64Encoded; }
From de1a822c1381652adc17c06aff4e6066b8b5a309 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 4 Dec 2021 11:13:57 +0800 Subject: [PATCH 21/27] Add verifyMessage --- nep-20.mediawiki | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index b3752f8c..b545f550 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -456,9 +456,11 @@ export interface IDapiProvider { // Signs the message with the specified account. // The algorithm used is ECDsa with SHA256. - // If `salt` is omitted, no salt will be used. // If `account` is omitted, the wallet should automatically select an account or prompt the user to select one. - signMessage(message: Base64Encoded, salt?: Base64Encoded, account?: UInt160): Base64Encoded; + signMessage(message: Base64Encoded, account?: UInt160): Base64Encoded; + + // Verify that the message is signed by the specified address or public key. + verifyMessage(message: Base64Encoded, signature: Base64Encoded, accountOrPubkey: UInt160 | ECPoint): boolean; }
From 5e9a49a3ddee40e12228dd7f4b7797fcac25b720 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 4 Dec 2021 11:19:03 +0800 Subject: [PATCH 22/27] Remove verifyMessage --- nep-20.mediawiki | 3 --- 1 file changed, 3 deletions(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index b545f550..eeeac2a5 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -459,9 +459,6 @@ export interface IDapiProvider { // If `account` is omitted, the wallet should automatically select an account or prompt the user to select one. signMessage(message: Base64Encoded, account?: UInt160): Base64Encoded; - // Verify that the message is signed by the specified address or public key. - verifyMessage(message: Base64Encoded, signature: Base64Encoded, accountOrPubkey: UInt160 | ECPoint): boolean; - }
From 161a3e78fb87f75ae588b95fa05f949dfc51f68e Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 4 Dec 2021 11:23:41 +0800 Subject: [PATCH 23/27] Improve signMessage --- nep-20.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index eeeac2a5..7c891d67 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -457,7 +457,7 @@ export interface IDapiProvider { // Signs the message with the specified account. // The algorithm used is ECDsa with SHA256. // If `account` is omitted, the wallet should automatically select an account or prompt the user to select one. - signMessage(message: Base64Encoded, account?: UInt160): Base64Encoded; + signMessage(message: Base64Encoded, account?: UInt160): { signature: Base64Encoded; account: UInt160; pubkey: ECPoint }; } From bace43334d25deb05704f245bc3cf173fcd2c57e Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 4 Dec 2021 11:27:27 +0800 Subject: [PATCH 24/27] Use Promise --- nep-20.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 7c891d67..51167488 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -457,7 +457,7 @@ export interface IDapiProvider { // Signs the message with the specified account. // The algorithm used is ECDsa with SHA256. // If `account` is omitted, the wallet should automatically select an account or prompt the user to select one. - signMessage(message: Base64Encoded, account?: UInt160): { signature: Base64Encoded; account: UInt160; pubkey: ECPoint }; + signMessage(message: Base64Encoded, account?: UInt160): Promise<{ signature: Base64Encoded; account: UInt160; pubkey: ECPoint }>; } From 67b282fe13bdc957978613f0523822072ea9bf07 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 4 Dec 2021 11:48:20 +0800 Subject: [PATCH 25/27] Add possible errors to methods --- nep-20.mediawiki | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/nep-20.mediawiki b/nep-20.mediawiki index 51167488..d0656411 100644 --- a/nep-20.mediawiki +++ b/nep-20.mediawiki @@ -405,58 +405,74 @@ export interface IDapiProvider { // Methods // Requests for authentication. Usually used to log in to a website. + // Possible errors: UNSUPPORTED, INVALID, TIMEOUT, CANCELED. authenticate(payload: AuthenticationChallengePayload): Promise; // Calls a contract offchain and get the execution result. + // Possible errors: INVALID, RPC_ERROR. call(invocation: InvocationArguments): Promise; // Gets all accounts in the current wallet. getAccounts(): Promise; // Gets the application log of the specified transaction. + // Possible errors: INVALID, RPC_ERROR. getApplicationLog(txid: UInt256): Promise; // Gets the balance of the specified account. // If `account` is omitted, the sum of all account balances in the current wallet should be returned. + // Possible errors: INVALID, NOTFOUND, FAILED, RPC_ERROR. getBalance(asset: UInt160, account?: UInt160): Promise; // Gets the block of the specified hash. + // Possible errors: INVALID, NOTFOUND, RPC_ERROR. getBlock(hash: UInt256): Promise; // Gets the block of the specified index. + // Possible errors: INVALID, NOTFOUND, RPC_ERROR. getBlock(index: number): Promise; // Gets the count of blocks in the blockchain. + // Possible errors: RPC_ERROR. getBlockCount(): Promise; // Gets the specified storage entry. + // Possible errors: INVALID, NOTFOUND, RPC_ERROR. getStorage(hash: UInt160, key: Base64Encoded): Promise; // Gets the information of the specified token. + // Possible errors: INVALID, NOTFOUND, FAILED, RPC_ERROR. getTokenInfo(hash: UInt160): Promise; // Gets the transaction of the specified hash. + // Possible errors: INVALID, NOTFOUND, RPC_ERROR. getTransaction(txid: UInt256): Promise; // Calls one or more contracts onchain and returns the hash of the transaction. + // Possible errors: INVALID, FAILED, TIMEOUT, CANCELED, RPC_ERROR. invoke(invocations: InvocationArguments[], signers?: Signer[], suggestedSystemFee?: Integer): Promise; // Calls one or more contracts onchain and return the transaction without relaying. + // Possible errors: INVALID, FAILED, TIMEOUT, CANCELED, RPC_ERROR. makeTransaction(invocations: InvocationArguments[], signers?: Signer[], suggestedSystemFee?: Integer): Promise; // Relays a transaction and returns the hash of it. + // Possible errors: INVALID, TIMEOUT, CANCELED, INSUFFICIENT_FUNDS, RPC_ERROR. relay(context: ContractParametersContext): Promise; // Sends assets to an account and returns the hash of the transaction. // If `from` is omitted, the wallet should automatically select an account or prompt the user to select one. + // Possible errors: INVALID, NOTFOUND, FAILED, TIMEOUT, CANCELED, INSUFFICIENT_FUNDS, RPC_ERROR. send(asset: UInt160, amount: Integer, to: UInt160, from?: UInt160): Promise; // Signs the transaction with the current wallet. Usually used for multi-signature transactions. + // Possible errors: UNSUPPORTED, INVALID, NOTFOUND, TIMEOUT, CANCELED. sign(context: ContractParametersContext): Promise; // Signs the message with the specified account. // The algorithm used is ECDsa with SHA256. // If `account` is omitted, the wallet should automatically select an account or prompt the user to select one. + // Possible errors: INVALID, NOTFOUND, TIMEOUT, CANCELED. signMessage(message: Base64Encoded, account?: UInt160): Promise<{ signature: Base64Encoded; account: UInt160; pubkey: ECPoint }>; } From f36ddd05c733cad2f42f2b9e6c0343d8f5a77bef Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 9 Dec 2021 13:52:27 +0800 Subject: [PATCH 26/27] Update authentication payloads --- nep-20.mediawiki => nep-21.mediawiki | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename nep-20.mediawiki => nep-21.mediawiki (97%) diff --git a/nep-20.mediawiki b/nep-21.mediawiki similarity index 97% rename from nep-20.mediawiki rename to nep-21.mediawiki index d0656411..ef00a9f0 100644 --- a/nep-20.mediawiki +++ b/nep-21.mediawiki @@ -1,5 +1,5 @@
-  NEP: 20
+  NEP: 21
   Title: Dapi for N3
   Author: Erik Zhang 
   Type: Standard
@@ -345,13 +345,14 @@ export type AuthenticationChallengePayload = {
     action: "Authentication";
     grant_type: "Signature";
     allowed_algorithms: ["ECDSA-P256"];
-    network: Network;
+    networks: Network[];
     nonce: string;
     timestamp: number;
 }
 
 export type AuthenticationResponsePayload = {
     algorithm: "ECDSA-P256";
+    network: Network;
     pubkey: ECPoint;
     address: Address;
     nonce: string;

From 10f5399c26725cb47b1bebd76359bb2acdca88ed Mon Sep 17 00:00:00 2001
From: Erik Zhang 
Date: Thu, 9 Dec 2021 14:00:49 +0800
Subject: [PATCH 27/27] Add requires

---
 nep-21.mediawiki | 1 +
 1 file changed, 1 insertion(+)

diff --git a/nep-21.mediawiki b/nep-21.mediawiki
index ef00a9f0..3862f9af 100644
--- a/nep-21.mediawiki
+++ b/nep-21.mediawiki
@@ -5,6 +5,7 @@
   Type: Standard
   Status: Accepted
   Created: 2021-11-24
+  Requires: 20
 
==Abstract==