suidouble 1.45.2 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +7 -0
- package/README.md +222 -131
- package/index.js +1 -3
- package/lib/SuiCliCommands.js +18 -25
- package/lib/SuiCoin.js +86 -138
- package/lib/SuiCoins.js +70 -31
- package/lib/SuiCommonMethods.js +40 -3
- package/lib/SuiEvent.js +54 -6
- package/lib/SuiInBrowser.js +145 -46
- package/lib/SuiInBrowserAdapter.js +164 -37
- package/lib/SuiLocalTestValidator.js +78 -25
- package/lib/SuiMaster.js +351 -126
- package/lib/SuiMemoryObjectStorage.js +66 -73
- package/lib/SuiObject.js +128 -153
- package/lib/SuiPackage.js +292 -187
- package/lib/SuiPackageModule.js +176 -221
- package/lib/SuiPaginatedResponse.js +288 -25
- package/lib/SuiPseudoRandomAddress.js +29 -2
- package/lib/SuiTransaction.js +115 -70
- package/lib/SuiUtils.js +179 -124
- package/package.json +30 -14
- package/test/build_modules.test.js +41 -0
- package/test/coins.test.js +17 -16
- package/test/custom_transaction.test.js +167 -0
- package/test/event_listeners.test.js +171 -0
- package/test/failed_transaction.test.js +184 -0
- package/test/name_service.test.js +28 -0
- package/test/owned_objects.test.js +148 -0
- package/test/rpc.test.js +3 -6
- package/test/sui_in_browser.test.js +2 -2
- package/test/sui_master_basic.test.js +4 -5
- package/test/sui_master_onlocal.test.js +84 -22
- package/test/sui_object_properties.test.js +85 -0
- package/test/test_move_contracts/different_types/Move.lock +18 -21
- package/test/test_move_contracts/different_types/sources/different_types.move +12 -12
- package/test/test_move_contracts/suidouble_chat/Move.lock +18 -22
- package/test/test_move_contracts/suidouble_chat/sources/suidouble_chat.move +9 -8
- package/tsconfig.json +15 -0
- package/types/index.d.ts +15 -0
- package/types/lib/SuiCliCommands.d.ts +6 -0
- package/types/lib/SuiCoin.d.ts +183 -0
- package/types/lib/SuiCoins.d.ts +93 -0
- package/types/lib/SuiCommonMethods.d.ts +37 -0
- package/types/lib/SuiEvent.d.ts +95 -0
- package/types/lib/SuiInBrowser.d.ts +189 -0
- package/types/lib/SuiInBrowserAdapter.d.ts +167 -0
- package/types/lib/SuiLocalTestValidator.d.ts +92 -0
- package/types/lib/SuiMaster.d.ts +333 -0
- package/types/lib/SuiMemoryObjectStorage.d.ts +96 -0
- package/types/lib/SuiObject.d.ts +135 -0
- package/types/lib/SuiPackage.d.ts +233 -0
- package/types/lib/SuiPackageModule.d.ts +139 -0
- package/types/lib/SuiPaginatedResponse.d.ts +148 -0
- package/types/lib/SuiPseudoRandomAddress.d.ts +33 -0
- package/types/lib/SuiTransaction.d.ts +92 -0
- package/types/lib/SuiUtils.d.ts +152 -0
- package/types/lib/data/icons.d.ts +12 -0
- package/lib/SuiTestScenario.js +0 -169
- package/test/sui_test_scenario.test.js +0 -61
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
export { normalizeSuiAddress };
|
|
2
|
+
/** Helpful methods using in different places of suidouble */
|
|
3
|
+
export default class SuiUtils extends SuiCommonMethods {
|
|
4
|
+
/**
|
|
5
|
+
* Attach the parameter input into transaction, to be used for moveCall
|
|
6
|
+
* accepts an Inputs.Pure (result of .pureInput) or type + value directly
|
|
7
|
+
*
|
|
8
|
+
* @param {Transaction} tx
|
|
9
|
+
* @param {string | PureInput} typeOrInput - string type name, or already-serialised Pure input `{ Pure: { bytes } }`
|
|
10
|
+
* @param {*} [value]
|
|
11
|
+
* @returns {Argument}
|
|
12
|
+
*/
|
|
13
|
+
static txInput(tx: Transaction, typeOrInput: string | PureInput, value?: any): Argument;
|
|
14
|
+
/**
|
|
15
|
+
* Returns and Inputs.Pure for a given type
|
|
16
|
+
* to be used as moveCall parameters
|
|
17
|
+
* type is 'u8', 'u16', 'u32', 'u64', 'u128', 'u256', 'address', 'bool', 'string', 'vector<u8>' ... 'vector<u256>'
|
|
18
|
+
*
|
|
19
|
+
* result may be passed as arguments to SuiPackage or SuiPackageModule moveCall functions params array:
|
|
20
|
+
* contract.moveCall('suidouble_chat', 'reply', [
|
|
21
|
+
* SuiUtils.pureInput('string', 'metadata')
|
|
22
|
+
* SuiUtils.pureInput('string', 'metadata')
|
|
23
|
+
* ]);
|
|
24
|
+
*
|
|
25
|
+
* if you are going to construct tx yourself, you'd better use SuiUtils.txInput static method
|
|
26
|
+
*
|
|
27
|
+
* @param {string} type
|
|
28
|
+
* @param {*} value
|
|
29
|
+
* @returns {CallArg}
|
|
30
|
+
*/
|
|
31
|
+
static pureInput(type: string, value: any): CallArg;
|
|
32
|
+
/**
|
|
33
|
+
* Convert sui's PureInput into bcs serialized bytes
|
|
34
|
+
* @param {PureInput} pureInput
|
|
35
|
+
*/
|
|
36
|
+
static pureInputToBytes(pureInput: PureInput): Uint8Array<ArrayBuffer>;
|
|
37
|
+
/**
|
|
38
|
+
* Decode a Move `vector<u8>` field into a UTF-8 string.
|
|
39
|
+
*
|
|
40
|
+
* Accepts the shapes SUI returns across representations:
|
|
41
|
+
* - base64 string (v2 gRPC/GraphQL JSON representation for byte vectors)
|
|
42
|
+
* - Uint8Array
|
|
43
|
+
* - array of numbers (legacy JSON-RPC shape)
|
|
44
|
+
*
|
|
45
|
+
* @param {string | Uint8Array | number[]} value
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
static bytesFieldToString(value: string | Uint8Array | number[]): string;
|
|
49
|
+
/**
|
|
50
|
+
* Wrapper for sui's utils normalizeSuiAddress
|
|
51
|
+
* Perform the following operations:
|
|
52
|
+
* <pre>
|
|
53
|
+
* 1. Make the address lower case
|
|
54
|
+
* 2. Prepend `0x` if the string does not start with `0x`.
|
|
55
|
+
* 3. Add more zeros if the length of the address(excluding `0x`) is less than `SUI_ADDRESS_LENGTH`
|
|
56
|
+
* </pre>
|
|
57
|
+
*
|
|
58
|
+
* @param {string} address
|
|
59
|
+
* @returns string
|
|
60
|
+
*/
|
|
61
|
+
static normalizeSuiAddress(address: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* Makes an instance of SuiGrpcClient pointed at a custom gRPC-web endpoint.
|
|
64
|
+
*
|
|
65
|
+
* `transportOptions` is passed through to GrpcWebFetchTransport — the same shape
|
|
66
|
+
* as `@protobuf-ts/grpcweb-transport`'s GrpcWebOptions:
|
|
67
|
+
* - baseUrl : string — required, the gRPC-web endpoint
|
|
68
|
+
* - format : 'text' | 'binary' — wire format, defaults to 'text'
|
|
69
|
+
* - fetchInit : RequestInit-ish — extra fetch options (credentials, cache, ...); `body`/`headers`/`method`/`signal` are reserved
|
|
70
|
+
* - fetch : typeof fetch — custom fetch implementation (useful for proxies, auth, logging)
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* const client = SuiUtils.suiClientForRPC('mainnet', {
|
|
74
|
+
* baseUrl: 'https://fullnode.mainnet.sui.io:443',
|
|
75
|
+
* format: 'binary',
|
|
76
|
+
* fetchInit: { credentials: 'include' },
|
|
77
|
+
* fetch: (url, init) => fetch(url, { ...init, headers: { ...init.headers, 'x-api-key': 'xxx' } }),
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* @param {SuiClientTypes.Network} network
|
|
81
|
+
* @param {GrpcWebOptions} transportOptions
|
|
82
|
+
* @returns {SuiGrpcClient}
|
|
83
|
+
*/
|
|
84
|
+
static suiClientForRPC(network: SuiClientTypes.Network, transportOptions: GrpcWebOptions): SuiGrpcClient;
|
|
85
|
+
/**
|
|
86
|
+
* Build a SuiGraphQLClient reusing the network of an existing SuiGrpcClient.
|
|
87
|
+
*
|
|
88
|
+
* Picks the default Sui GraphQL endpoint for the network unless `overrides.url` is set.
|
|
89
|
+
* `overrides` is forwarded to SuiGraphQLClient (fetch, headers, queries, mvr, url).
|
|
90
|
+
*
|
|
91
|
+
* @param {SuiGrpcClient} grpcClient
|
|
92
|
+
* @param {Object} [overrides]
|
|
93
|
+
* @param {?string} [overrides.url]
|
|
94
|
+
* @param {?typeof fetch} [overrides.fetch]
|
|
95
|
+
* @param {?Object.<string, string>} [overrides.headers]
|
|
96
|
+
* @returns {SuiGraphQLClient}
|
|
97
|
+
*/
|
|
98
|
+
static suiGraphQLClientFromGrpc(grpcClient: SuiGrpcClient, overrides?: {
|
|
99
|
+
url?: string | null;
|
|
100
|
+
fetch?: typeof fetch | null;
|
|
101
|
+
headers?: {
|
|
102
|
+
[x: string]: string;
|
|
103
|
+
} | null;
|
|
104
|
+
}): SuiGraphQLClient;
|
|
105
|
+
/**
|
|
106
|
+
* Makes an instance for SuiGrpcClient for a specific chain, eg: 'mainnet' | 'testnet' | 'devnet' | 'localnet'
|
|
107
|
+
* @param {SuiClientTypes.Network} network
|
|
108
|
+
* @returns {SuiGrpcClient}
|
|
109
|
+
*/
|
|
110
|
+
static suiClientFor(network: SuiClientTypes.Network): SuiGrpcClient;
|
|
111
|
+
/**
|
|
112
|
+
* Normalize client parameter into a SuiGrpcClient, accepting:
|
|
113
|
+
* - an existing SuiGrpcClient instance
|
|
114
|
+
* - a SuiLocalTestValidator instance
|
|
115
|
+
* - a string chain name: 'local' | 'localnet' | 'dev' | 'devnet' | 'test' | 'testnet' | 'main' | 'mainnet'
|
|
116
|
+
* - a legacy client object (sniffs network from endpoint / connection.fullnode / providerName)
|
|
117
|
+
*
|
|
118
|
+
* @param {SuiGrpcClient | string | Object} clientParam
|
|
119
|
+
* @returns {SuiGrpcClient | null}
|
|
120
|
+
*/
|
|
121
|
+
static normalizeClient(clientParam: SuiGrpcClient | string | any): SuiGrpcClient | null;
|
|
122
|
+
/**
|
|
123
|
+
* Strip an optional "sui:" prefix and map short aliases ('local', 'dev', 'test', 'main')
|
|
124
|
+
* to full network names. Returns null if the string doesn't match a known network.
|
|
125
|
+
*
|
|
126
|
+
* @param {string} s
|
|
127
|
+
* @returns {SuiClientTypes.Network | null}
|
|
128
|
+
*/
|
|
129
|
+
static normalizeNetworkString(s: string): SuiClientTypes.Network | null;
|
|
130
|
+
/**
|
|
131
|
+
* Extracts a SuiClientTypes.Network string from various inputs used historically by suidouble.
|
|
132
|
+
*
|
|
133
|
+
* @param {string | Object} clientParam
|
|
134
|
+
* @returns {SuiClientTypes.Network | null}
|
|
135
|
+
*/
|
|
136
|
+
static _sniffNetwork(clientParam: string | any): SuiClientTypes.Network | null;
|
|
137
|
+
}
|
|
138
|
+
export type Argument = import("@mysten/sui/transactions").Argument;
|
|
139
|
+
export type CallArg = import("@mysten/sui/transactions").CallArg;
|
|
140
|
+
export type PureInput = {
|
|
141
|
+
Pure: {
|
|
142
|
+
bytes: string;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
export type SuiGrpcClientOptions = import("@mysten/sui/grpc").SuiGrpcClientOptions;
|
|
146
|
+
export type GrpcWebOptions = import("@mysten/sui/grpc").GrpcWebOptions;
|
|
147
|
+
import { normalizeSuiAddress } from '@mysten/sui/utils';
|
|
148
|
+
import SuiCommonMethods from './SuiCommonMethods.js';
|
|
149
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
150
|
+
import type { SuiClientTypes } from "@mysten/sui/client";
|
|
151
|
+
import { SuiGrpcClient } from '@mysten/sui/grpc';
|
|
152
|
+
import { SuiGraphQLClient } from '@mysten/sui/graphql';
|
package/lib/SuiTestScenario.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import SuiCommonMethods from './SuiCommonMethods.js';
|
|
2
|
-
import SuiLocalTestValidator from './SuiLocalTestValidator.js';
|
|
3
|
-
import SuiMaster from './SuiMaster.js';
|
|
4
|
-
import SuiUtils from './SuiUtils.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export default class SuiTestScenario extends SuiCommonMethods {
|
|
8
|
-
constructor(params = {}) {
|
|
9
|
-
super(params);
|
|
10
|
-
|
|
11
|
-
this._path = params.path; // path to Move package's root
|
|
12
|
-
this._client = null;
|
|
13
|
-
|
|
14
|
-
this._defaultAs = null; // 'as'(string for pseudo-random keypair generator) for default user and package's owner
|
|
15
|
-
// (we will publish and init from this user)
|
|
16
|
-
this._currentAs = null; // 'as' for current wrapped transaction
|
|
17
|
-
|
|
18
|
-
this._masters = { // suiMaster and package for each 'as'
|
|
19
|
-
};
|
|
20
|
-
this._packages = {
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
this._publishedPackageId = null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
get currentAs() {
|
|
27
|
-
return this._currentAs;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
arg(type, value) {
|
|
31
|
-
return SuiUtils.pureInput(type, value);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Start local test validator and set up `as` as owner of package deploy transaction.
|
|
36
|
-
* Package will be deployed with method `init`, as we try to mimic Sui Move's test_scenario
|
|
37
|
-
* @param {String} as
|
|
38
|
-
*/
|
|
39
|
-
async begin(as) {
|
|
40
|
-
this._client = await SuiLocalTestValidator.launch({debug: true});
|
|
41
|
-
this._defaultAs = as;
|
|
42
|
-
this._currentAs = as;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Shut down test validator and finish test scenario
|
|
47
|
-
*/
|
|
48
|
-
async end() {
|
|
49
|
-
await SuiLocalTestValidator.stop();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Deploy the package. Move will execute it's init function.
|
|
54
|
-
*/
|
|
55
|
-
async init() {
|
|
56
|
-
if (!this._defaultAs) {
|
|
57
|
-
throw new Error('please call .begin(as) first');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
this._currentAs = this._defaultAs;
|
|
61
|
-
await this.initMaster(this._defaultAs);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Temorary assign user to `as`
|
|
67
|
-
* @param {String} as
|
|
68
|
-
* @param {Function} func
|
|
69
|
-
*/
|
|
70
|
-
async next_tx(as, func) {
|
|
71
|
-
if (!this._defaultAs) {
|
|
72
|
-
throw new Error('please call .begin(as) first');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
await this.initMaster(as);
|
|
77
|
-
this._currentAs = as;
|
|
78
|
-
await func(this);
|
|
79
|
-
this._currentAs = this._defaultAs;
|
|
80
|
-
} catch (e) {
|
|
81
|
-
throw e;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async nextTx(as, func) {
|
|
85
|
-
return this.next_tx(as, func);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
take_from_sender(typeName) {
|
|
89
|
-
const asAsAddress = this._masters[this._currentAs].address;
|
|
90
|
-
const objectStorage = this._masters[this._currentAs].objectStorage; // it's same object for different 'as' connected to the same provider, but we don't care here
|
|
91
|
-
return objectStorage.findMostRecent((object)=>{
|
|
92
|
-
return (object.typeName == typeName && object.isOwnedBy(asAsAddress));
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
takeFromSender(typeName) {
|
|
96
|
-
return this.take_from_sender(typeName);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
take_shared(typeName) {
|
|
100
|
-
const objectStorage = this._masters[this._currentAs].objectStorage; // it's same object for different 'as' connected to the same provider, but we don't care here
|
|
101
|
-
return objectStorage.findMostRecent((object)=>{
|
|
102
|
-
return (object.isShared && object.typeName == typeName);
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
takeShared(typeName) {
|
|
106
|
-
return this.take_shared(typeName);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
take_immutable(typeName) {
|
|
110
|
-
const objectStorage = this._masters[this._currentAs].objectStorage; // it's same object for different 'as' connected to the same provider, but we don't care here
|
|
111
|
-
return objectStorage.findMostRecent((object)=>{
|
|
112
|
-
return (object.isImmutable && object.typeName == typeName);
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
takeImmutable(typeName) {
|
|
116
|
-
return this.take_immutable(typeName);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async moveCall(moduleName, methodName, params) {
|
|
120
|
-
if (!this._currentAs) {
|
|
121
|
-
throw new Error('please call moveCall inside .next_tx(as, ()=>{}) wrapper');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
await this._packages[this._currentAs].modules[moduleName].moveCall(methodName, params);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async initMaster(as) {
|
|
128
|
-
if (this._masters[as]) {
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const suiMaster = new SuiMaster({debug: this._debug, as: as, client: this._client, });
|
|
133
|
-
|
|
134
|
-
await suiMaster.initialize();
|
|
135
|
-
await suiMaster.requestSuiFromFaucet();
|
|
136
|
-
|
|
137
|
-
const addPackageParams = {};
|
|
138
|
-
if (this._publishedPackageId) {
|
|
139
|
-
// already pulished
|
|
140
|
-
addPackageParams.id = this._publishedPackageId;
|
|
141
|
-
} else {
|
|
142
|
-
// to be build and published
|
|
143
|
-
addPackageParams.path = this._path;
|
|
144
|
-
}
|
|
145
|
-
const addedPackage = suiMaster.addPackage(addPackageParams);
|
|
146
|
-
// addedPackage.addEventListener('added', (data)=>{
|
|
147
|
-
// const object = data.detail;
|
|
148
|
-
// if (object && !this._objects[object.address]) { // there may be few same object instances in different suiMaster's.
|
|
149
|
-
// this._objects[object.address] = object;
|
|
150
|
-
// }
|
|
151
|
-
// });
|
|
152
|
-
|
|
153
|
-
if (!this._publishedPackageId) {
|
|
154
|
-
await addedPackage.publish();
|
|
155
|
-
this._publishedPackageId = addedPackage.id;
|
|
156
|
-
|
|
157
|
-
if (!this._publishedPackageId) {
|
|
158
|
-
this.log('can not publish a package');
|
|
159
|
-
}
|
|
160
|
-
} else {
|
|
161
|
-
await addedPackage.isOnChain(); // check modules etc for other user
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
this._masters[as] = suiMaster;
|
|
166
|
-
this._packages[as] = addedPackage;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
import t from 'tap';
|
|
4
|
-
import { SuiTestScenario } from '../index.js';
|
|
5
|
-
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
|
|
9
|
-
const { test } = t;
|
|
10
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
-
const __dirname = path.dirname(__filename);
|
|
12
|
-
|
|
13
|
-
let testScenario = null;
|
|
14
|
-
|
|
15
|
-
test('initialization', async t => {
|
|
16
|
-
testScenario = new SuiTestScenario({
|
|
17
|
-
path: path.join(__dirname, './test_move_contracts/suidouble_chat/'),
|
|
18
|
-
debug: false,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
await testScenario.begin('admin');
|
|
22
|
-
await testScenario.init();
|
|
23
|
-
|
|
24
|
-
t.equal(testScenario.currentAs, 'admin');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('checking takeShared', async t => {
|
|
28
|
-
t.plan(4);
|
|
29
|
-
|
|
30
|
-
await testScenario.nextTx('admin', async()=>{
|
|
31
|
-
const chatShop = testScenario.takeShared('ChatShop');
|
|
32
|
-
|
|
33
|
-
t.ok(chatShop.address); // there should be some address
|
|
34
|
-
t.ok(`${chatShop.address}`.indexOf('0x') === 0); // adress is string starting with '0x'
|
|
35
|
-
|
|
36
|
-
await testScenario.moveCall('suidouble_chat', 'post', [chatShop.address, testScenario.arg('string', 'posting a message'), testScenario.arg('string', 'metadata')]);
|
|
37
|
-
const chatTopMessage = testScenario.takeShared('ChatTopMessage');
|
|
38
|
-
|
|
39
|
-
t.ok(chatTopMessage.address); // there should be some address
|
|
40
|
-
t.ok(`${chatTopMessage.address}`.indexOf('0x') === 0); // adress is string starting with '0x'
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('checking takeOwned', async t => {
|
|
45
|
-
t.plan(3);
|
|
46
|
-
|
|
47
|
-
await testScenario.nextTx('somebody', async()=>{
|
|
48
|
-
const chatTopMessage = testScenario.takeShared('ChatTopMessage');
|
|
49
|
-
t.ok(chatTopMessage.address); // there should be some address
|
|
50
|
-
|
|
51
|
-
await testScenario.moveCall('suidouble_chat', 'reply', [chatTopMessage.address, testScenario.arg('string', 'posting a response'), testScenario.arg('string', 'metadata')]);
|
|
52
|
-
const chatResponse = testScenario.takeFromSender('ChatResponse');
|
|
53
|
-
|
|
54
|
-
t.ok(chatResponse.address); // there should be some address
|
|
55
|
-
t.ok(`${chatResponse.address}`.indexOf('0x') === 0); // adress is string starting with '0x'
|
|
56
|
-
});
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('finishing the test scenario', async t => {
|
|
60
|
-
await testScenario.end();
|
|
61
|
-
});
|