@openzeppelin/relayer-plugin-channels 0.7.0 → 0.8.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/dist/client/types.d.ts +4 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/plugin/handler.d.ts.map +1 -1
- package/dist/plugin/handler.js +14 -1
- package/dist/plugin/simulation.d.ts +33 -5
- package/dist/plugin/simulation.d.ts.map +1 -1
- package/dist/plugin/simulation.js +71 -23
- package/dist/plugin/types.d.ts +4 -0
- package/dist/plugin/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/client/types.d.ts
CHANGED
|
@@ -62,6 +62,10 @@ export interface ChannelsTransactionResponse {
|
|
|
62
62
|
hash: string | null;
|
|
63
63
|
/** Transaction status */
|
|
64
64
|
status: string | null;
|
|
65
|
+
/** Present only for read-only calls: the base64-encoded xdr.ScVal return value */
|
|
66
|
+
returnValue?: string;
|
|
67
|
+
/** Present only for read-only calls: the latest ledger at simulation time */
|
|
68
|
+
latestLedger?: number;
|
|
65
69
|
/** Optional metadata (logs and traces) */
|
|
66
70
|
metadata?: {
|
|
67
71
|
logs?: LogEntry[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/plugin/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AASvE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAWxD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,WAAW,GACd;IAAE,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAA;CAAE,GAAG,IAAI,CAkB1E;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/plugin/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AASvE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAWxD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,WAAW,GACd;IAAE,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAA;CAAE,GAAG,IAAI,CAkB1E;AAsOD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAElE"}
|
package/dist/plugin/handler.js
CHANGED
|
@@ -71,6 +71,18 @@ async function handleXdrSubmit(xdrStr, fundRelayer, fundAddress, network, networ
|
|
|
71
71
|
return (0, submit_1.submitWithFeeBumpAndWait)(fundRelayer, validated.toXDR(), network, maxFee, api, tracker);
|
|
72
72
|
}
|
|
73
73
|
async function handleFuncAuthSubmit(func, auth, api, pool, fundRelayer, fundAddress, network, networkPassphrase, acquireOptions, tracker) {
|
|
74
|
+
// Simulate once — used for both read-only detection and transaction assembly
|
|
75
|
+
const simulation = await (0, simulation_1.simulateTransaction)(func, auth, fundAddress, fundRelayer, networkPassphrase);
|
|
76
|
+
if (simulation.isReadOnly) {
|
|
77
|
+
console.log(`[channels] Read-only call detected, returning simulation result`);
|
|
78
|
+
return {
|
|
79
|
+
transactionId: null,
|
|
80
|
+
status: 'readonly',
|
|
81
|
+
hash: null,
|
|
82
|
+
returnValue: simulation.returnValue,
|
|
83
|
+
latestLedger: simulation.latestLedger,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
74
86
|
let poolLock;
|
|
75
87
|
try {
|
|
76
88
|
poolLock = await pool.acquire(acquireOptions);
|
|
@@ -92,7 +104,8 @@ async function handleFuncAuthSubmit(func, auth, api, pool, fundRelayer, fundAddr
|
|
|
92
104
|
details: { network_type: channelStatus.network_type, relayerId: poolLock.relayerId },
|
|
93
105
|
});
|
|
94
106
|
}
|
|
95
|
-
|
|
107
|
+
// Assemble the transaction using the cached simulation result — no second RPC call
|
|
108
|
+
const built = (0, simulation_1.buildWithChannel)(func, auth, { address: channelInfo.address, sequence: channelStatus.sequence_number }, networkPassphrase, simulation.rawSimResult);
|
|
96
109
|
const signedTx = await (0, submit_1.signWithChannelAndFund)(built, channelRelayer, fundRelayer, channelInfo.address, fundAddress, networkPassphrase);
|
|
97
110
|
const maxFee = (0, fee_1.calculateMaxFee)(signedTx, acquireOptions.limitedContracts);
|
|
98
111
|
await tracker?.checkBudget(maxFee);
|
|
@@ -1,17 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* simulation.ts
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* transaction with
|
|
4
|
+
* Simulate a Soroban transaction once (using a throwaway source account) and
|
|
5
|
+
* reuse the result to both detect read-only calls and assemble the final
|
|
6
|
+
* transaction with the real channel account. This avoids a redundant network
|
|
7
|
+
* round-trip to the RPC node.
|
|
7
8
|
*/
|
|
8
|
-
import { Transaction, xdr } from '@stellar/stellar-sdk';
|
|
9
|
+
import { rpc, Transaction, xdr } from '@stellar/stellar-sdk';
|
|
9
10
|
import { Relayer } from '@openzeppelin/relayer-sdk';
|
|
10
11
|
export interface ChannelAccount {
|
|
11
12
|
address: string;
|
|
12
13
|
sequence: string;
|
|
13
14
|
}
|
|
14
|
-
export
|
|
15
|
+
export interface SimulationResult {
|
|
16
|
+
/** Whether the call is read-only (no auth + no read-write footprint). */
|
|
17
|
+
isReadOnly: boolean;
|
|
18
|
+
/** base64-encoded xdr.ScVal return value, present when isReadOnly is true. */
|
|
19
|
+
returnValue?: string;
|
|
20
|
+
/** Latest ledger at simulation time. */
|
|
21
|
+
latestLedger?: number;
|
|
22
|
+
/** Raw simulation response — used by buildWithChannel to assemble the tx. */
|
|
23
|
+
rawSimResult: rpc.Api.RawSimulateTransactionResponse;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Simulate a transaction to obtain the full simulation response and detect
|
|
27
|
+
* whether the call is read-only.
|
|
28
|
+
*
|
|
29
|
+
* Uses a throwaway source account (sequence "0") because `simulateTransaction`
|
|
30
|
+
* does not validate sequence numbers. This lets us simulate before acquiring a
|
|
31
|
+
* channel pool slot.
|
|
32
|
+
*
|
|
33
|
+
* A call is read-only when:
|
|
34
|
+
* 1. Zero auth entries — no one needs to authorize anything
|
|
35
|
+
* 2. Zero read-write footprint entries — no ledger state will be modified
|
|
36
|
+
*/
|
|
37
|
+
export declare function simulateTransaction(func: xdr.HostFunction, auth: xdr.SorobanAuthorizationEntry[] | undefined, sourceAddress: string, relayer: Relayer, networkPassphrase: string): Promise<SimulationResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Build and assemble a transaction using a channel account and an already-
|
|
40
|
+
* obtained simulation result. No additional network calls are made.
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildWithChannel(func: xdr.HostFunction, auth: xdr.SorobanAuthorizationEntry[] | undefined, channel: ChannelAccount, networkPassphrase: string, simResult: rpc.Api.RawSimulateTransactionResponse): Transaction;
|
|
15
43
|
/** Extract human-readable message + error type from simulation error diagnostic events */
|
|
16
44
|
export declare function parseSimulationError(error: string): string;
|
|
17
45
|
//# sourceMappingURL=simulation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simulation.d.ts","sourceRoot":"","sources":["../../src/plugin/simulation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"simulation.d.ts","sourceRoot":"","sources":["../../src/plugin/simulation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,GAAG,EAAE,WAAW,EAAsB,GAAG,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAgD,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,UAAU,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,CAAC;CACtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,gBAAgB,CAAC,CA8E3B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,OAAO,EAAE,cAAc,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,GAChD,WAAW,CAsCb;AACD,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAe1D"}
|
|
@@ -2,30 +2,38 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* simulation.ts
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* transaction with
|
|
5
|
+
* Simulate a Soroban transaction once (using a throwaway source account) and
|
|
6
|
+
* reuse the result to both detect read-only calls and assemble the final
|
|
7
|
+
* transaction with the real channel account. This avoids a redundant network
|
|
8
|
+
* round-trip to the RPC node.
|
|
8
9
|
*/
|
|
9
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.
|
|
11
|
+
exports.simulateTransaction = simulateTransaction;
|
|
12
|
+
exports.buildWithChannel = buildWithChannel;
|
|
11
13
|
exports.parseSimulationError = parseSimulationError;
|
|
12
14
|
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
13
15
|
const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
|
|
14
16
|
const constants_1 = require("./constants");
|
|
15
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Simulate a transaction to obtain the full simulation response and detect
|
|
19
|
+
* whether the call is read-only.
|
|
20
|
+
*
|
|
21
|
+
* Uses a throwaway source account (sequence "0") because `simulateTransaction`
|
|
22
|
+
* does not validate sequence numbers. This lets us simulate before acquiring a
|
|
23
|
+
* channel pool slot.
|
|
24
|
+
*
|
|
25
|
+
* A call is read-only when:
|
|
26
|
+
* 1. Zero auth entries — no one needs to authorize anything
|
|
27
|
+
* 2. Zero read-write footprint entries — no ledger state will be modified
|
|
28
|
+
*/
|
|
29
|
+
async function simulateTransaction(func, auth, sourceAddress, relayer, networkPassphrase) {
|
|
16
30
|
const now = Math.floor(Date.now() / 1000);
|
|
17
|
-
|
|
18
|
-
// Build inner transaction (source = channel, op source = fund)
|
|
19
|
-
const transaction = new stellar_sdk_1.TransactionBuilder(new stellar_sdk_1.Account(channel.address, channel.sequence), {
|
|
31
|
+
const transaction = new stellar_sdk_1.TransactionBuilder(new stellar_sdk_1.Account(sourceAddress, '0'), {
|
|
20
32
|
fee: constants_1.SIMULATION.DEFAULT_FEE,
|
|
21
33
|
networkPassphrase,
|
|
22
34
|
timebounds: { minTime: constants_1.SIMULATION.MIN_TIME_BOUND, maxTime: now + constants_1.SIMULATION.MAX_TIME_BOUND_OFFSET_SECONDS },
|
|
23
35
|
})
|
|
24
|
-
.addOperation(stellar_sdk_1.Operation.invokeHostFunction({
|
|
25
|
-
func,
|
|
26
|
-
auth,
|
|
27
|
-
// No explicit source: default to transaction source (channel account)
|
|
28
|
-
}))
|
|
36
|
+
.addOperation(stellar_sdk_1.Operation.invokeHostFunction({ func, auth }))
|
|
29
37
|
.build();
|
|
30
38
|
let rpcResponse;
|
|
31
39
|
try {
|
|
@@ -33,18 +41,14 @@ async function simulateAndBuildWithChannel(func, auth, channel, _fundAddress, re
|
|
|
33
41
|
jsonrpc: '2.0',
|
|
34
42
|
id: Math.floor(Math.random() * 1e8).toString(),
|
|
35
43
|
method: 'simulateTransaction',
|
|
36
|
-
params: {
|
|
37
|
-
transaction: transaction.toXDR(),
|
|
38
|
-
},
|
|
44
|
+
params: { transaction: transaction.toXDR() },
|
|
39
45
|
});
|
|
40
46
|
}
|
|
41
47
|
catch (err) {
|
|
42
48
|
throw (0, relayer_sdk_1.pluginError)('Simulation network request failed', {
|
|
43
49
|
code: 'SIMULATION_NETWORK_ERROR',
|
|
44
50
|
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
45
|
-
details: {
|
|
46
|
-
message: err instanceof Error ? err.message : String(err),
|
|
47
|
-
},
|
|
51
|
+
details: { message: err instanceof Error ? err.message : String(err) },
|
|
48
52
|
});
|
|
49
53
|
}
|
|
50
54
|
if (rpcResponse.error) {
|
|
@@ -68,17 +72,61 @@ async function simulateAndBuildWithChannel(func, auth, channel, _fundAddress, re
|
|
|
68
72
|
details: { error: parseSimulationError(simResult.error) },
|
|
69
73
|
});
|
|
70
74
|
}
|
|
75
|
+
// Read-only detection
|
|
76
|
+
const results = simResult.results;
|
|
77
|
+
const hasAuth = (results?.[0]?.auth?.length ?? 0) > 0;
|
|
78
|
+
let hasReadWrite = false;
|
|
79
|
+
if (simResult.transactionData) {
|
|
80
|
+
try {
|
|
81
|
+
const sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.fromXDR(simResult.transactionData, 'base64');
|
|
82
|
+
hasReadWrite = sorobanData.resources().footprint().readWrite().length > 0;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// If we can't parse transactionData, treat as not read-only (safe fallback)
|
|
86
|
+
hasReadWrite = true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const isReadOnly = !hasAuth && !hasReadWrite;
|
|
90
|
+
if (isReadOnly) {
|
|
91
|
+
console.log(`[channels] Read-only call detected via simulation`);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
isReadOnly,
|
|
95
|
+
returnValue: isReadOnly ? results?.[0]?.xdr : undefined,
|
|
96
|
+
latestLedger: simResult.latestLedger,
|
|
97
|
+
rawSimResult: simResult,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Build and assemble a transaction using a channel account and an already-
|
|
102
|
+
* obtained simulation result. No additional network calls are made.
|
|
103
|
+
*/
|
|
104
|
+
function buildWithChannel(func, auth, channel, networkPassphrase, simResult) {
|
|
105
|
+
const now = Math.floor(Date.now() / 1000);
|
|
106
|
+
console.debug(`[channels] Building tx: channel=${channel.address}, seq=${channel.sequence}, auth_count=${auth?.length ?? 0}`);
|
|
107
|
+
// Build inner transaction (source = channel)
|
|
108
|
+
const transaction = new stellar_sdk_1.TransactionBuilder(new stellar_sdk_1.Account(channel.address, channel.sequence), {
|
|
109
|
+
fee: constants_1.SIMULATION.DEFAULT_FEE,
|
|
110
|
+
networkPassphrase,
|
|
111
|
+
timebounds: { minTime: constants_1.SIMULATION.MIN_TIME_BOUND, maxTime: now + constants_1.SIMULATION.MAX_TIME_BOUND_OFFSET_SECONDS },
|
|
112
|
+
})
|
|
113
|
+
.addOperation(stellar_sdk_1.Operation.invokeHostFunction({
|
|
114
|
+
func,
|
|
115
|
+
auth,
|
|
116
|
+
// No explicit source: default to transaction source (channel account)
|
|
117
|
+
}))
|
|
118
|
+
.build();
|
|
71
119
|
try {
|
|
72
|
-
// Use SDK's assembleTransaction to apply simulation results
|
|
120
|
+
// Use SDK's assembleTransaction to apply the cached simulation results
|
|
73
121
|
const prepared = stellar_sdk_1.rpc.assembleTransaction(transaction, simResult).build();
|
|
74
122
|
const resourceFee = prepared.toEnvelope().v1().tx().ext().sorobanData()?.resourceFee();
|
|
75
|
-
console.debug(`[channels]
|
|
123
|
+
console.debug(`[channels] Assembly complete: resourceFee=${resourceFee}`);
|
|
76
124
|
return prepared;
|
|
77
125
|
}
|
|
78
126
|
catch (err) {
|
|
79
127
|
console.error(`[channels] Assembly error: ${err instanceof Error ? err.message : String(err)}`);
|
|
80
|
-
throw (0, relayer_sdk_1.pluginError)('
|
|
81
|
-
code: '
|
|
128
|
+
throw (0, relayer_sdk_1.pluginError)('Transaction assembly failed', {
|
|
129
|
+
code: 'ASSEMBLY_FAILED',
|
|
82
130
|
status: constants_1.HTTP_STATUS.INTERNAL_SERVER_ERROR,
|
|
83
131
|
details: {
|
|
84
132
|
message: err instanceof Error ? err.message : String(err),
|
package/dist/plugin/types.d.ts
CHANGED
|
@@ -24,6 +24,10 @@ export interface ChannelAccountsResponse {
|
|
|
24
24
|
transactionId: string | null;
|
|
25
25
|
status: string | null;
|
|
26
26
|
hash: string | null;
|
|
27
|
+
/** Present only for read-only calls: the base64-encoded xdr.ScVal return value */
|
|
28
|
+
returnValue?: string;
|
|
29
|
+
/** Present only for read-only calls: the latest ledger at simulation time */
|
|
30
|
+
latestLedger?: number;
|
|
27
31
|
}
|
|
28
32
|
/**
|
|
29
33
|
* Management request structure
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAA;CAAE,CAAC;AAEzF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAEhD,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAA;CAAE,CAAC;AAEzF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,qBAAqB,GAAG,oBAAoB,CAAC;QACrD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,OAAO,CAAC;IACZ,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB"}
|