@layerzerolabs/lz-iotal1-sdk-v2 3.0.143
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/CHANGELOG.md +32 -0
- package/README.md +19 -0
- package/deployments/iotal1-mainnet/blocked_message_lib.json +58 -0
- package/deployments/iotal1-mainnet/blocked_msglib_ptb_builder.json +58 -0
- package/deployments/iotal1-mainnet/call.json +46 -0
- package/deployments/iotal1-mainnet/counter.json +85 -0
- package/deployments/iotal1-mainnet/dvn.json +49 -0
- package/deployments/iotal1-mainnet/dvn_call_type.json +45 -0
- package/deployments/iotal1-mainnet/dvn_fee_lib.json +59 -0
- package/deployments/iotal1-mainnet/dvn_layerzero.json +56 -0
- package/deployments/iotal1-mainnet/dvn_ptb_builder.json +45 -0
- package/deployments/iotal1-mainnet/endpoint_ptb_builder.json +70 -0
- package/deployments/iotal1-mainnet/endpoint_v2.json +86 -0
- package/deployments/iotal1-mainnet/executor.json +49 -0
- package/deployments/iotal1-mainnet/executor_call_type.json +45 -0
- package/deployments/iotal1-mainnet/executor_fee_lib.json +60 -0
- package/deployments/iotal1-mainnet/executor_layerzero.json +56 -0
- package/deployments/iotal1-mainnet/executor_ptb_builder.json +45 -0
- package/deployments/iotal1-mainnet/layerzero_views.json +46 -0
- package/deployments/iotal1-mainnet/message_lib_common.json +47 -0
- package/deployments/iotal1-mainnet/msglib_ptb_builder_call_types.json +45 -0
- package/deployments/iotal1-mainnet/multi_call.json +45 -0
- package/deployments/iotal1-mainnet/oapp.json +50 -0
- package/deployments/iotal1-mainnet/object-BlockedMessageLib.json +9 -0
- package/deployments/iotal1-mainnet/object-BlockedMsglibPtbBuilder.json +9 -0
- package/deployments/iotal1-mainnet/object-Counter.json +9 -0
- package/deployments/iotal1-mainnet/object-CounterAdminCap.json +9 -0
- package/deployments/iotal1-mainnet/object-CounterOApp.json +9 -0
- package/deployments/iotal1-mainnet/object-DVN.json +5 -0
- package/deployments/iotal1-mainnet/object-DVNCap.json +9 -0
- package/deployments/iotal1-mainnet/object-DVNFeeLib.json +9 -0
- package/deployments/iotal1-mainnet/object-EndpointPtbBuilder.json +9 -0
- package/deployments/iotal1-mainnet/object-EndpointPtbBuilderAdminCap.json +9 -0
- package/deployments/iotal1-mainnet/object-EndpointV2.json +9 -0
- package/deployments/iotal1-mainnet/object-EndpointV2AdminCap.json +9 -0
- package/deployments/iotal1-mainnet/object-Executor.json +5 -0
- package/deployments/iotal1-mainnet/object-ExecutorCap.json +9 -0
- package/deployments/iotal1-mainnet/object-ExecutorFeeLib.json +9 -0
- package/deployments/iotal1-mainnet/object-ExecutorOwnerCap.json +5 -0
- package/deployments/iotal1-mainnet/object-OFTComposerManager.json +9 -0
- package/deployments/iotal1-mainnet/object-PackageWhitelistValidator.json +9 -0
- package/deployments/iotal1-mainnet/object-PriceFeed.json +9 -0
- package/deployments/iotal1-mainnet/object-PriceFeedOwnerCap.json +9 -0
- package/deployments/iotal1-mainnet/object-SimpleMessageLib.json +9 -0
- package/deployments/iotal1-mainnet/object-SimpleMessageLibAdminCap.json +9 -0
- package/deployments/iotal1-mainnet/object-SmlPtbBuilder.json +9 -0
- package/deployments/iotal1-mainnet/object-Treasury.json +9 -0
- package/deployments/iotal1-mainnet/object-TreasuryAdminCap.json +9 -0
- package/deployments/iotal1-mainnet/object-ULN302.json +9 -0
- package/deployments/iotal1-mainnet/object-ULN302AdminCap.json +9 -0
- package/deployments/iotal1-mainnet/object-Uln302PtbBuilder.json +9 -0
- package/deployments/iotal1-mainnet/object-Uln302Verification.json +9 -0
- package/deployments/iotal1-mainnet/object-WorkerRegistry.json +9 -0
- package/deployments/iotal1-mainnet/object-ZroCoinMetadata.json +9 -0
- package/deployments/iotal1-mainnet/object-ZroTreasuryCap.json +9 -0
- package/deployments/iotal1-mainnet/oft_common.json +61 -0
- package/deployments/iotal1-mainnet/package_whitelist_validator.json +113 -0
- package/deployments/iotal1-mainnet/price_feed.json +70 -0
- package/deployments/iotal1-mainnet/price_feed_call_types.json +45 -0
- package/deployments/iotal1-mainnet/ptb_move_call.json +48 -0
- package/deployments/iotal1-mainnet/simple_message_lib.json +69 -0
- package/deployments/iotal1-mainnet/simple_msglib_ptb_builder.json +58 -0
- package/deployments/iotal1-mainnet/treasury.json +69 -0
- package/deployments/iotal1-mainnet/uln_302.json +87 -0
- package/deployments/iotal1-mainnet/uln_302_ptb_builder.json +58 -0
- package/deployments/iotal1-mainnet/uln_common.json +49 -0
- package/deployments/iotal1-mainnet/utils.json +57 -0
- package/deployments/iotal1-mainnet/worker_common.json +46 -0
- package/deployments/iotal1-mainnet/worker_registry.json +58 -0
- package/deployments/iotal1-mainnet/zro.json +67 -0
- package/deployments/iotal1-sandbox-local/blocked_message_lib.json +58 -0
- package/deployments/iotal1-sandbox-local/blocked_msglib_ptb_builder.json +58 -0
- package/deployments/iotal1-sandbox-local/call.json +46 -0
- package/deployments/iotal1-sandbox-local/counter.json +148 -0
- package/deployments/iotal1-sandbox-local/dvn.json +49 -0
- package/deployments/iotal1-sandbox-local/dvn_call_type.json +73 -0
- package/deployments/iotal1-sandbox-local/dvn_fee_lib.json +59 -0
- package/deployments/iotal1-sandbox-local/dvn_layerzero.json +56 -0
- package/deployments/iotal1-sandbox-local/dvn_ptb_builder.json +45 -0
- package/deployments/iotal1-sandbox-local/endpoint_ptb_builder.json +70 -0
- package/deployments/iotal1-sandbox-local/endpoint_v2.json +86 -0
- package/deployments/iotal1-sandbox-local/executor.json +49 -0
- package/deployments/iotal1-sandbox-local/executor_call_type.json +73 -0
- package/deployments/iotal1-sandbox-local/executor_fee_lib.json +60 -0
- package/deployments/iotal1-sandbox-local/executor_layerzero.json +56 -0
- package/deployments/iotal1-sandbox-local/executor_ptb_builder.json +45 -0
- package/deployments/iotal1-sandbox-local/layerzero_views.json +46 -0
- package/deployments/iotal1-sandbox-local/message_lib_common.json +47 -0
- package/deployments/iotal1-sandbox-local/msglib_ptb_builder_call_types.json +45 -0
- package/deployments/iotal1-sandbox-local/multi_call.json +45 -0
- package/deployments/iotal1-sandbox-local/oapp.json +50 -0
- package/deployments/iotal1-sandbox-local/object-BlockedMessageLib.json +9 -0
- package/deployments/iotal1-sandbox-local/object-BlockedMsglibPtbBuilder.json +9 -0
- package/deployments/iotal1-sandbox-local/object-Counter.json +9 -0
- package/deployments/iotal1-sandbox-local/object-CounterAdminCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-CounterOApp.json +9 -0
- package/deployments/iotal1-sandbox-local/object-DVN.json +5 -0
- package/deployments/iotal1-sandbox-local/object-DVNCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-DVNFeeLib.json +9 -0
- package/deployments/iotal1-sandbox-local/object-EndpointPtbBuilder.json +9 -0
- package/deployments/iotal1-sandbox-local/object-EndpointPtbBuilderAdminCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-EndpointV2.json +9 -0
- package/deployments/iotal1-sandbox-local/object-EndpointV2AdminCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-Executor.json +5 -0
- package/deployments/iotal1-sandbox-local/object-ExecutorCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-ExecutorFeeLib.json +9 -0
- package/deployments/iotal1-sandbox-local/object-ExecutorOwnerCap.json +5 -0
- package/deployments/iotal1-sandbox-local/object-PackageWhitelistValidator.json +9 -0
- package/deployments/iotal1-sandbox-local/object-PriceFeed.json +9 -0
- package/deployments/iotal1-sandbox-local/object-PriceFeedOwnerCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-SimpleMessageLib.json +9 -0
- package/deployments/iotal1-sandbox-local/object-SimpleMessageLibAdminCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-SmlPtbBuilder.json +9 -0
- package/deployments/iotal1-sandbox-local/object-Treasury.json +9 -0
- package/deployments/iotal1-sandbox-local/object-TreasuryAdminCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-ULN302.json +9 -0
- package/deployments/iotal1-sandbox-local/object-ULN302AdminCap.json +9 -0
- package/deployments/iotal1-sandbox-local/object-Uln302PtbBuilder.json +9 -0
- package/deployments/iotal1-sandbox-local/object-Uln302Verification.json +9 -0
- package/deployments/iotal1-sandbox-local/object-WorkerRegistry.json +9 -0
- package/deployments/iotal1-sandbox-local/object-ZroCoinMetadata.json +9 -0
- package/deployments/iotal1-sandbox-local/object-ZroTreasuryCap.json +9 -0
- package/deployments/iotal1-sandbox-local/package_whitelist_validator.json +113 -0
- package/deployments/iotal1-sandbox-local/price_feed.json +98 -0
- package/deployments/iotal1-sandbox-local/price_feed_call_types.json +45 -0
- package/deployments/iotal1-sandbox-local/ptb_move_call.json +48 -0
- package/deployments/iotal1-sandbox-local/simple_message_lib.json +69 -0
- package/deployments/iotal1-sandbox-local/simple_msglib_ptb_builder.json +58 -0
- package/deployments/iotal1-sandbox-local/treasury.json +97 -0
- package/deployments/iotal1-sandbox-local/uln_302.json +87 -0
- package/deployments/iotal1-sandbox-local/uln_302_ptb_builder.json +58 -0
- package/deployments/iotal1-sandbox-local/uln_common.json +49 -0
- package/deployments/iotal1-sandbox-local/utils.json +78 -0
- package/deployments/iotal1-sandbox-local/worker_common.json +46 -0
- package/deployments/iotal1-sandbox-local/worker_registry.json +58 -0
- package/deployments/iotal1-sandbox-local/zro.json +67 -0
- package/deployments/iotal1-testnet/blocked_message_lib.json +58 -0
- package/deployments/iotal1-testnet/blocked_msglib_ptb_builder.json +58 -0
- package/deployments/iotal1-testnet/call.json +46 -0
- package/deployments/iotal1-testnet/counter.json +85 -0
- package/deployments/iotal1-testnet/dvn.json +49 -0
- package/deployments/iotal1-testnet/dvn_call_type.json +45 -0
- package/deployments/iotal1-testnet/dvn_fee_lib.json +59 -0
- package/deployments/iotal1-testnet/dvn_layerzero.json +56 -0
- package/deployments/iotal1-testnet/dvn_ptb_builder.json +45 -0
- package/deployments/iotal1-testnet/endpoint_ptb_builder.json +70 -0
- package/deployments/iotal1-testnet/endpoint_v2.json +86 -0
- package/deployments/iotal1-testnet/executor.json +49 -0
- package/deployments/iotal1-testnet/executor_call_type.json +45 -0
- package/deployments/iotal1-testnet/executor_fee_lib.json +60 -0
- package/deployments/iotal1-testnet/executor_layerzero.json +56 -0
- package/deployments/iotal1-testnet/executor_ptb_builder.json +45 -0
- package/deployments/iotal1-testnet/layerzero_views.json +46 -0
- package/deployments/iotal1-testnet/message_lib_common.json +47 -0
- package/deployments/iotal1-testnet/msglib_ptb_builder_call_types.json +45 -0
- package/deployments/iotal1-testnet/multi_call.json +45 -0
- package/deployments/iotal1-testnet/oapp.json +50 -0
- package/deployments/iotal1-testnet/object-BlockedMessageLib.json +9 -0
- package/deployments/iotal1-testnet/object-BlockedMsglibPtbBuilder.json +9 -0
- package/deployments/iotal1-testnet/object-Counter.json +9 -0
- package/deployments/iotal1-testnet/object-CounterAdminCap.json +9 -0
- package/deployments/iotal1-testnet/object-CounterOApp.json +9 -0
- package/deployments/iotal1-testnet/object-DVN.json +5 -0
- package/deployments/iotal1-testnet/object-DVNCap.json +9 -0
- package/deployments/iotal1-testnet/object-DVNFeeLib.json +9 -0
- package/deployments/iotal1-testnet/object-EndpointPtbBuilder.json +9 -0
- package/deployments/iotal1-testnet/object-EndpointPtbBuilderAdminCap.json +9 -0
- package/deployments/iotal1-testnet/object-EndpointV2.json +9 -0
- package/deployments/iotal1-testnet/object-EndpointV2AdminCap.json +9 -0
- package/deployments/iotal1-testnet/object-Executor.json +5 -0
- package/deployments/iotal1-testnet/object-ExecutorCap.json +9 -0
- package/deployments/iotal1-testnet/object-ExecutorFeeLib.json +9 -0
- package/deployments/iotal1-testnet/object-ExecutorOwnerCap.json +5 -0
- package/deployments/iotal1-testnet/object-PackageWhitelistValidator.json +9 -0
- package/deployments/iotal1-testnet/object-PriceFeed.json +9 -0
- package/deployments/iotal1-testnet/object-PriceFeedOwnerCap.json +9 -0
- package/deployments/iotal1-testnet/object-SimpleMessageLib.json +9 -0
- package/deployments/iotal1-testnet/object-SimpleMessageLibAdminCap.json +9 -0
- package/deployments/iotal1-testnet/object-SmlPtbBuilder.json +9 -0
- package/deployments/iotal1-testnet/object-Treasury.json +9 -0
- package/deployments/iotal1-testnet/object-TreasuryAdminCap.json +9 -0
- package/deployments/iotal1-testnet/object-ULN302.json +9 -0
- package/deployments/iotal1-testnet/object-ULN302AdminCap.json +9 -0
- package/deployments/iotal1-testnet/object-Uln302PtbBuilder.json +9 -0
- package/deployments/iotal1-testnet/object-Uln302Verification.json +9 -0
- package/deployments/iotal1-testnet/object-WorkerRegistry.json +9 -0
- package/deployments/iotal1-testnet/object-ZroCoinMetadata.json +9 -0
- package/deployments/iotal1-testnet/object-ZroTreasuryCap.json +9 -0
- package/deployments/iotal1-testnet/package_whitelist_validator.json +113 -0
- package/deployments/iotal1-testnet/price_feed.json +70 -0
- package/deployments/iotal1-testnet/price_feed_call_types.json +45 -0
- package/deployments/iotal1-testnet/ptb_move_call.json +48 -0
- package/deployments/iotal1-testnet/simple_message_lib.json +69 -0
- package/deployments/iotal1-testnet/simple_msglib_ptb_builder.json +58 -0
- package/deployments/iotal1-testnet/treasury.json +69 -0
- package/deployments/iotal1-testnet/uln_302.json +87 -0
- package/deployments/iotal1-testnet/uln_302_ptb_builder.json +58 -0
- package/deployments/iotal1-testnet/uln_common.json +49 -0
- package/deployments/iotal1-testnet/utils.json +57 -0
- package/deployments/iotal1-testnet/worker_common.json +46 -0
- package/deployments/iotal1-testnet/worker_registry.json +58 -0
- package/deployments/iotal1-testnet/zro.json +67 -0
- package/dist/index.cjs +11279 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +5824 -0
- package/dist/index.d.ts +5824 -0
- package/dist/index.mjs +11107 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +68 -0
- package/src/bcs/dvn.ts +7 -0
- package/src/bcs/endpoint.ts +7 -0
- package/src/bcs/executor.ts +27 -0
- package/src/bcs/index.ts +8 -0
- package/src/bcs/messaging-fee.ts +6 -0
- package/src/bcs/move-call.ts +28 -0
- package/src/bcs/oapp.ts +14 -0
- package/src/bcs/price-feed.ts +21 -0
- package/src/bcs/uln.ts +15 -0
- package/src/generated/addresses.ts +344 -0
- package/src/index.ts +5 -0
- package/src/module-manager.ts +360 -0
- package/src/modules/call.ts +245 -0
- package/src/modules/endpoint.ts +2417 -0
- package/src/modules/index.ts +10 -0
- package/src/modules/layerzero-views.ts +205 -0
- package/src/modules/message-libs/blocked-message-lib.ts +112 -0
- package/src/modules/message-libs/index.ts +4 -0
- package/src/modules/message-libs/simple-message-lib.ts +270 -0
- package/src/modules/message-libs/uln302.ts +827 -0
- package/src/modules/oapps/counter.ts +458 -0
- package/src/modules/oapps/index.ts +3 -0
- package/src/modules/oapps/oapp.ts +744 -0
- package/src/modules/ptb-builders/blocked-message-lib-ptb-builder.ts +49 -0
- package/src/modules/ptb-builders/dvn-ptb-builder.ts +58 -0
- package/src/modules/ptb-builders/endpoint-ptb-builder.ts +520 -0
- package/src/modules/ptb-builders/executor-ptb-builder.ts +58 -0
- package/src/modules/ptb-builders/index.ts +9 -0
- package/src/modules/ptb-builders/package-whitelist-validator.ts +142 -0
- package/src/modules/ptb-builders/ptb-builder.ts +357 -0
- package/src/modules/ptb-builders/simple-message-lib-ptb-builder.ts +53 -0
- package/src/modules/ptb-builders/uln302-ptb-builder.ts +222 -0
- package/src/modules/utils.ts +902 -0
- package/src/modules/workers/dvn-fee-lib.ts +89 -0
- package/src/modules/workers/dvn-layerzero.ts +85 -0
- package/src/modules/workers/dvn.ts +1727 -0
- package/src/modules/workers/executor-fee-lib.ts +94 -0
- package/src/modules/workers/executor-layerzero.ts +79 -0
- package/src/modules/workers/executor.ts +1170 -0
- package/src/modules/workers/index.ts +10 -0
- package/src/modules/workers/price-feed.ts +575 -0
- package/src/modules/workers/treasury.ts +295 -0
- package/src/modules/workers/worker-registry.ts +110 -0
- package/src/modules/zro.ts +94 -0
- package/src/resource.ts +104 -0
- package/src/sdk.ts +183 -0
- package/src/types/dvn.ts +20 -0
- package/src/types/endpoint.ts +16 -0
- package/src/types/errors.ts +10 -0
- package/src/types/executor.ts +23 -0
- package/src/types/index.ts +13 -0
- package/src/types/layerzero-views.ts +59 -0
- package/src/types/message-lib.ts +38 -0
- package/src/types/modules.ts +36 -0
- package/src/types/move-types.ts +24 -0
- package/src/types/oapp.ts +6 -0
- package/src/types/options.ts +333 -0
- package/src/types/price-feed.ts +21 -0
- package/src/types/ptb-builder.ts +29 -0
- package/src/types/simulation.ts +8 -0
- package/src/utils/argument.ts +198 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/move-call-object-fetcher.ts +105 -0
- package/src/utils/non-sender-object-validator.ts +102 -0
- package/src/utils/package-allowlist-validator.ts +134 -0
- package/src/utils/ptb-validator.ts +14 -0
- package/src/utils/share-object-validator.ts +37 -0
- package/src/utils/transaction.ts +157 -0
- package/src/utils/type-name.ts +99 -0
- package/src/utils/validate-with-details.ts +50 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ObjectOwner } from '@iota/iota-sdk/client'
|
|
2
|
+
|
|
3
|
+
import { MoveCallWithObjectDetails } from './move-call-object-fetcher'
|
|
4
|
+
import { IPTBValidator } from './ptb-validator'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* NonSenderObjectValidator ensures objects are not owned by the transaction sender
|
|
8
|
+
*
|
|
9
|
+
* In Iota, this validator checks that objects are:
|
|
10
|
+
* - Shared: globally accessible, mutations require consensus
|
|
11
|
+
* - Immutable: can't change after creation
|
|
12
|
+
* - Owned by another address (not the sender)
|
|
13
|
+
*
|
|
14
|
+
* This prevents the sender from using their own owned objects in the transaction
|
|
15
|
+
*/
|
|
16
|
+
export class NonSenderObjectValidator implements IPTBValidator {
|
|
17
|
+
private sender: string
|
|
18
|
+
|
|
19
|
+
constructor(sender: string) {
|
|
20
|
+
this.sender = sender
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Validates that objects are not owned by the sender
|
|
25
|
+
* @param moveCallsWithDetails - Array of move calls with object details
|
|
26
|
+
* @throws Error if any object is owned by the sender
|
|
27
|
+
*/
|
|
28
|
+
validate(moveCallsWithDetails: MoveCallWithObjectDetails[]): void {
|
|
29
|
+
for (const { objectDetails } of moveCallsWithDetails) {
|
|
30
|
+
for (const [objectId, objectResponse] of objectDetails) {
|
|
31
|
+
const owner = objectResponse.data?.owner
|
|
32
|
+
if (owner == null) {
|
|
33
|
+
throw new Error(`Object ${objectId} has no owner`)
|
|
34
|
+
}
|
|
35
|
+
// Validate that object is not owned by the sender
|
|
36
|
+
if (!this.isValidOwnership(owner)) {
|
|
37
|
+
const ownerType = this.getOwnershipType(owner)
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Object ${objectId} is owned by the sender (${this.sender}). ` +
|
|
40
|
+
`Only Shared, Immutable, or objects owned by other addresses are allowed. ` +
|
|
41
|
+
`Current ownership: ${ownerType}`
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Checks if the ownership is valid (not owned by sender)
|
|
50
|
+
* @param owner - The object owner to check
|
|
51
|
+
* @returns true if ownership is valid (Shared, Immutable, or owned by another address)
|
|
52
|
+
*/
|
|
53
|
+
private isValidOwnership(owner: ObjectOwner): boolean {
|
|
54
|
+
// Shared objects are valid
|
|
55
|
+
if (typeof owner === 'object' && 'Shared' in owner) {
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Immutable objects are valid
|
|
60
|
+
if (owner === 'Immutable') {
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Objects owned by another address are valid
|
|
65
|
+
if (typeof owner === 'object' && 'AddressOwner' in owner && owner.AddressOwner !== this.sender) {
|
|
66
|
+
return true
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Objects owned by another object are valid
|
|
70
|
+
if (typeof owner === 'object' && 'ObjectOwner' in owner) {
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// If owned by sender, it's invalid
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Gets a human-readable description of the ownership type
|
|
80
|
+
* @param owner - The object owner
|
|
81
|
+
* @returns String description of ownership type
|
|
82
|
+
*/
|
|
83
|
+
private getOwnershipType(owner: ObjectOwner): string {
|
|
84
|
+
if (typeof owner === 'object' && 'Shared' in owner) {
|
|
85
|
+
return `Shared (initial_shared_version: ${owner.Shared.initial_shared_version})`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (owner === 'Immutable') {
|
|
89
|
+
return 'Immutable'
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (typeof owner === 'object' && 'AddressOwner' in owner) {
|
|
93
|
+
return `AddressOwner: ${owner.AddressOwner}`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (typeof owner === 'object' && 'ObjectOwner' in owner) {
|
|
97
|
+
return `ObjectOwner: ${owner.ObjectOwner}`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return 'Unknown ownership type'
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { MoveCallWithObjectDetails } from './move-call-object-fetcher'
|
|
2
|
+
import { IPTBValidator } from './ptb-validator'
|
|
3
|
+
import { PackageWhitelistValidator as PackageWhitelistSDK } from '../modules/ptb-builders/package-whitelist-validator'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* PackageAllowlistValidator ensures all function calls and objects belong to allowlisted packages
|
|
7
|
+
* This validator checks that:
|
|
8
|
+
* 1. All function calls target approved packages
|
|
9
|
+
* 2. All object arguments come from approved packages
|
|
10
|
+
*
|
|
11
|
+
* If local packageWhitelist is empty, it will use the PTB whitelist contract for validation
|
|
12
|
+
* If local packageWhitelist is provided, it will use only the local whitelist (contract is ignored)
|
|
13
|
+
*/
|
|
14
|
+
export class PackageAllowlistValidator implements IPTBValidator {
|
|
15
|
+
private packageWhitelist: Set<string>
|
|
16
|
+
private validator?: PackageWhitelistSDK
|
|
17
|
+
|
|
18
|
+
constructor(packageWhitelist: string[] = [], validator?: PackageWhitelistSDK) {
|
|
19
|
+
if (packageWhitelist.length == 0 && validator == null) {
|
|
20
|
+
throw new Error('PackageAllowlistValidator requires either a packageWhitelist or a validator')
|
|
21
|
+
}
|
|
22
|
+
this.packageWhitelist = new Set(packageWhitelist)
|
|
23
|
+
this.validator = validator
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Validates that all function calls and object arguments belong to whitelisted packages
|
|
28
|
+
* @param moveCallsWithDetails - Array of move calls with object details
|
|
29
|
+
* @throws Error if any function call or object belongs to a non-whitelisted package
|
|
30
|
+
*/
|
|
31
|
+
async validate(moveCallsWithDetails: MoveCallWithObjectDetails[]): Promise<void> {
|
|
32
|
+
const allPackages = new Set<string>()
|
|
33
|
+
|
|
34
|
+
// Collect packages from function calls
|
|
35
|
+
for (const { moveCall } of moveCallsWithDetails) {
|
|
36
|
+
const packageId = moveCall.function.package
|
|
37
|
+
if (packageId === '') {
|
|
38
|
+
throw new Error('Move call package is missing')
|
|
39
|
+
}
|
|
40
|
+
allPackages.add(packageId)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Collect packages from objects
|
|
44
|
+
for (const { objectDetails } of moveCallsWithDetails) {
|
|
45
|
+
for (const [objectId, objectResponse] of objectDetails) {
|
|
46
|
+
if (!objectResponse.data) {
|
|
47
|
+
throw new Error(`Object ${objectId} not found`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const packageId = this.extractPackageIdFromType(objectResponse.data.type)
|
|
51
|
+
if (packageId == null) {
|
|
52
|
+
throw new Error(`Could not extract package ID from object ${objectId}`)
|
|
53
|
+
}
|
|
54
|
+
allPackages.add(packageId)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Validate all packages at once
|
|
59
|
+
const isAllValid = await this.validatePackages(Array.from(allPackages))
|
|
60
|
+
// Check result - if any package failed, throw error
|
|
61
|
+
if (!isAllValid) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`One or more packages are not allowlisted. Packages: [${Array.from(allPackages).join(', ')}]`
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Validate multiple packages at once
|
|
70
|
+
* @param packages - Array of package IDs to validate
|
|
71
|
+
* @returns Object mapping package ID to validation result
|
|
72
|
+
*/
|
|
73
|
+
private async validatePackages(packages: string[]): Promise<boolean> {
|
|
74
|
+
if (packages.length === 0) {
|
|
75
|
+
return true
|
|
76
|
+
}
|
|
77
|
+
// If custom whitelist is provided, use it first
|
|
78
|
+
if (this.packageWhitelist.size > 0) {
|
|
79
|
+
// Check if ALL packages are in whitelist - if any fails, return false
|
|
80
|
+
for (const packageId of packages) {
|
|
81
|
+
if (!this.packageWhitelist.has(packageId)) {
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return true
|
|
86
|
+
} else {
|
|
87
|
+
// Use the contract's validate function to validate all packages at once
|
|
88
|
+
try {
|
|
89
|
+
return await this.validator!.validate(packages)
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.warn(`Failed to check whitelist:`, error)
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Extracts package ID from object type string
|
|
99
|
+
* Object types are in format: "packageId::module::struct<generics>"
|
|
100
|
+
* @param objectType - The object type string
|
|
101
|
+
* @returns The package ID or null if extraction fails
|
|
102
|
+
*/
|
|
103
|
+
private extractPackageIdFromType(objectType: string | null | undefined): string | null {
|
|
104
|
+
if (objectType == null) {
|
|
105
|
+
return null
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Object type format: "0x123abc::module_name::struct_name<T1, T2>"
|
|
109
|
+
// We want to extract the package ID (0x123abc)
|
|
110
|
+
const parts = objectType.split('::')
|
|
111
|
+
if (parts.length < 2) {
|
|
112
|
+
return null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const packageId = parts[0]
|
|
116
|
+
|
|
117
|
+
// Validate that it looks like a package ID (starts with 0x and has hex characters)
|
|
118
|
+
if (!packageId.startsWith('0x') || packageId.length < 3) {
|
|
119
|
+
return null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return packageId
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get available packages for error messages
|
|
127
|
+
*/
|
|
128
|
+
private getAvailablePackagesList(): string {
|
|
129
|
+
if (this.packageWhitelist.size > 0) {
|
|
130
|
+
return Array.from(this.packageWhitelist).join(', ')
|
|
131
|
+
}
|
|
132
|
+
return 'contract whitelist'
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { MoveCallWithObjectDetails } from './move-call-object-fetcher'
|
|
2
|
+
|
|
3
|
+
export interface ObjectFetchOptions {
|
|
4
|
+
showOwner?: boolean
|
|
5
|
+
showType?: boolean
|
|
6
|
+
showContent?: boolean
|
|
7
|
+
showBcs?: boolean
|
|
8
|
+
showDisplay?: boolean
|
|
9
|
+
showStorageRebate?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface IPTBValidator {
|
|
13
|
+
validate(moveCallsWithDetails: MoveCallWithObjectDetails[], sender?: string): void | Promise<void>
|
|
14
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ObjectOwner } from '@iota/iota-sdk/client'
|
|
2
|
+
|
|
3
|
+
import { MoveCallWithObjectDetails } from './move-call-object-fetcher'
|
|
4
|
+
import { IPTBValidator } from './ptb-validator'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ShareObjectValidator ensures all object arguments are Shared or Immutable
|
|
8
|
+
* This is the default validator for PTB operations
|
|
9
|
+
*/
|
|
10
|
+
export class ShareObjectValidator implements IPTBValidator {
|
|
11
|
+
/**
|
|
12
|
+
* Validates move calls with pre-fetched object details
|
|
13
|
+
* @param moveCallsWithDetails - Array of move calls with object details
|
|
14
|
+
* @throws Error if any object is not Shared/Immutable
|
|
15
|
+
*/
|
|
16
|
+
validate(moveCallsWithDetails: MoveCallWithObjectDetails[]): void {
|
|
17
|
+
for (const { objectDetails } of moveCallsWithDetails) {
|
|
18
|
+
for (const [objectId, objectResponse] of objectDetails) {
|
|
19
|
+
if (objectResponse.data?.owner == null) {
|
|
20
|
+
throw new Error(`Object ${objectId} does not have owner`)
|
|
21
|
+
}
|
|
22
|
+
if (!this.isSharedOrImmutable(objectResponse.data.owner)) {
|
|
23
|
+
throw new Error(`Object ${objectId} is not Shared/Immutable`)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Checks if an object owner is Shared or Immutable
|
|
31
|
+
* @param owner - The object owner to check
|
|
32
|
+
* @returns true if the owner is Shared or Immutable, false otherwise
|
|
33
|
+
*/
|
|
34
|
+
protected isSharedOrImmutable(owner: ObjectOwner): boolean {
|
|
35
|
+
return (typeof owner === 'object' && 'Shared' in owner) || owner === 'Immutable'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { IotaClient, IotaExecutionResult, IotaTransactionBlockResponse } from '@iota/iota-sdk/client'
|
|
2
|
+
import { Keypair } from '@iota/iota-sdk/cryptography'
|
|
3
|
+
import { Ed25519Keypair } from '@iota/iota-sdk/keypairs/ed25519'
|
|
4
|
+
import { Transaction } from '@iota/iota-sdk/transactions'
|
|
5
|
+
import { fromBase64 } from '@iota/iota-sdk/utils'
|
|
6
|
+
|
|
7
|
+
import { MoveAbortError, SimulateResult, UnclassifiedError } from '../types'
|
|
8
|
+
|
|
9
|
+
export async function simulateTransaction(
|
|
10
|
+
iotaClient: IotaClient,
|
|
11
|
+
tx: Transaction,
|
|
12
|
+
sender?: string
|
|
13
|
+
): Promise<SimulateResult[]> {
|
|
14
|
+
const resolvedSender = determineSenderAddress(tx, sender)
|
|
15
|
+
const { results, error } = await iotaClient.devInspectTransactionBlock({
|
|
16
|
+
transactionBlock: tx,
|
|
17
|
+
sender: resolvedSender,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
21
|
+
if (error != undefined && error != null) {
|
|
22
|
+
throw handleError(error)
|
|
23
|
+
}
|
|
24
|
+
if (results === undefined || results === null) {
|
|
25
|
+
throw new Error('No results found')
|
|
26
|
+
}
|
|
27
|
+
const lastCommandResults: IotaExecutionResult = results[results.length - 1]
|
|
28
|
+
|
|
29
|
+
if (lastCommandResults.returnValues === undefined) {
|
|
30
|
+
throw new Error('No return values found')
|
|
31
|
+
}
|
|
32
|
+
return lastCommandResults.returnValues.map((result) => {
|
|
33
|
+
return {
|
|
34
|
+
value: typeof result[0] === 'string' ? fromBase64(result[0]) : new Uint8Array(result[0]),
|
|
35
|
+
type: result[1],
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function simulateTransactionMultiResult(
|
|
41
|
+
iotaClient: IotaClient,
|
|
42
|
+
tx: Transaction,
|
|
43
|
+
resultIndex: number[],
|
|
44
|
+
sender?: string
|
|
45
|
+
): Promise<SimulateResult[][]> {
|
|
46
|
+
const resolvedSender = determineSenderAddress(tx, sender)
|
|
47
|
+
const { results, error } = await iotaClient.devInspectTransactionBlock({
|
|
48
|
+
transactionBlock: tx,
|
|
49
|
+
sender: resolvedSender,
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
53
|
+
if (error != undefined && error != null) {
|
|
54
|
+
throw handleError(error)
|
|
55
|
+
}
|
|
56
|
+
if (results === undefined || results === null) {
|
|
57
|
+
throw new Error('No results found')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const selectedResults: IotaExecutionResult[] = resultIndex.map((idx) => {
|
|
61
|
+
return results[idx]
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return selectedResults.map((result) => {
|
|
65
|
+
if (result.returnValues === undefined) {
|
|
66
|
+
throw new Error('No return values found')
|
|
67
|
+
}
|
|
68
|
+
return result.returnValues.map((result) => {
|
|
69
|
+
return {
|
|
70
|
+
value: typeof result[0] === 'string' ? fromBase64(result[0]) : new Uint8Array(result[0]),
|
|
71
|
+
type: result[1],
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function validateTransaction(
|
|
78
|
+
client: IotaClient,
|
|
79
|
+
signer: Keypair,
|
|
80
|
+
tx: Transaction
|
|
81
|
+
): Promise<IotaTransactionBlockResponse> {
|
|
82
|
+
tx.setSenderIfNotSet(signer.getPublicKey().toIotaAddress())
|
|
83
|
+
const result = await client.signAndExecuteTransaction({
|
|
84
|
+
signer,
|
|
85
|
+
transaction: tx,
|
|
86
|
+
options: {
|
|
87
|
+
showEffects: true,
|
|
88
|
+
showObjectChanges: true,
|
|
89
|
+
showEvents: true,
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
if (result.effects?.status.status !== 'success') {
|
|
94
|
+
throw new Error(result.effects?.status.error)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
await client.waitForTransaction({ digest: result.digest })
|
|
98
|
+
return result
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Execute simulate using a moveCall function
|
|
103
|
+
* @param client - The Iota client
|
|
104
|
+
* @param moveCallFn - Function that adds moveCall to the transaction (supports both sync and async, any return type)
|
|
105
|
+
* @param parser - Function to parse the result
|
|
106
|
+
* @returns The parsed result
|
|
107
|
+
*/
|
|
108
|
+
export async function executeSimulate<T>(
|
|
109
|
+
client: IotaClient,
|
|
110
|
+
moveCallFn: (tx: Transaction) => unknown,
|
|
111
|
+
parser: (result: { value: Uint8Array }[]) => T
|
|
112
|
+
): Promise<T> {
|
|
113
|
+
const tx = new Transaction()
|
|
114
|
+
await moveCallFn(tx)
|
|
115
|
+
const result = await simulateTransaction(client, tx)
|
|
116
|
+
return parser(result)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Determines the appropriate sender address using fallback hierarchy:
|
|
121
|
+
* 1. Use provided sender if available
|
|
122
|
+
* 2. Use transaction's existing sender if valid
|
|
123
|
+
* 3. Generate a random sender as last resort
|
|
124
|
+
*
|
|
125
|
+
* @param tx - The transaction to get sender from
|
|
126
|
+
* @param preferredSender - Optional sender address to prioritize
|
|
127
|
+
* @returns The determined sender address
|
|
128
|
+
*/
|
|
129
|
+
function determineSenderAddress(tx: Transaction, preferredSender?: string): string {
|
|
130
|
+
//eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
131
|
+
if (preferredSender) return preferredSender
|
|
132
|
+
|
|
133
|
+
const existingSender = tx.getData().sender
|
|
134
|
+
if (typeof existingSender === 'string') return existingSender
|
|
135
|
+
|
|
136
|
+
return Ed25519Keypair.generate().toIotaAddress()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function handleError(e: string): unknown {
|
|
140
|
+
if (e.includes('ExecutionError')) {
|
|
141
|
+
const majorStatusMatch = e.match(/major_status:\s([A-Z_]+)/)
|
|
142
|
+
if (majorStatusMatch !== null) {
|
|
143
|
+
const major_status = majorStatusMatch[1]
|
|
144
|
+
if (major_status === 'ABORTED') {
|
|
145
|
+
const subStatusMatch = e.match(/sub_status:\sSome\((\d+)\)/)
|
|
146
|
+
if (subStatusMatch === null) {
|
|
147
|
+
return new MoveAbortError(Number.NEGATIVE_INFINITY, e)
|
|
148
|
+
} else {
|
|
149
|
+
return new MoveAbortError(Number(subStatusMatch[1]), e)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
return new UnclassifiedError(e)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return new Error(e)
|
|
157
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import sha3 from 'js-sha3'
|
|
2
|
+
|
|
3
|
+
import { ModuleManager } from '../module-manager'
|
|
4
|
+
import { CallTypeName, LzTypeName, Modules } from '../types'
|
|
5
|
+
|
|
6
|
+
// Predefined type names
|
|
7
|
+
const TYPE_CONFIG = {
|
|
8
|
+
[LzTypeName.EndpointQuoteParam]: { pkg: Modules.Endpoint, module: 'endpoint_quote', type: 'QuoteParam' },
|
|
9
|
+
[LzTypeName.EndpointSendParam]: { pkg: Modules.Endpoint, module: 'endpoint_send', type: 'SendParam' },
|
|
10
|
+
[LzTypeName.MessageLibQuoteParam]: { pkg: Modules.Endpoint, module: 'message_lib_quote', type: 'QuoteParam' },
|
|
11
|
+
[LzTypeName.MessageLibSendParam]: { pkg: Modules.Endpoint, module: 'message_lib_send', type: 'SendParam' },
|
|
12
|
+
[LzTypeName.MessageLibSendResult]: { pkg: Modules.Endpoint, module: 'message_lib_send', type: 'SendResult' },
|
|
13
|
+
[LzTypeName.MessageLibSetConfigParam]: {
|
|
14
|
+
pkg: Modules.Endpoint,
|
|
15
|
+
module: 'message_lib_set_config',
|
|
16
|
+
type: 'SetConfigParam',
|
|
17
|
+
},
|
|
18
|
+
[LzTypeName.MessagingFee]: { pkg: Modules.Endpoint, module: 'messaging_fee', type: 'MessagingFee' },
|
|
19
|
+
[LzTypeName.MessagingReceipt]: { pkg: Modules.Endpoint, module: 'messaging_receipt', type: 'MessagingReceipt' },
|
|
20
|
+
[LzTypeName.EndpointLzReceiveParam]: { pkg: Modules.Endpoint, module: 'lz_receive', type: 'LzReceiveParam' },
|
|
21
|
+
[LzTypeName.EndpointLzComposeParam]: { pkg: Modules.Endpoint, module: 'lz_compose', type: 'LzComposeParam' },
|
|
22
|
+
[LzTypeName.MoveCall]: { pkg: Modules.Call, module: 'move_call', type: 'MoveCall' },
|
|
23
|
+
[LzTypeName.CallVoid]: { pkg: Modules.Call, module: 'call', type: 'Void' },
|
|
24
|
+
} as const
|
|
25
|
+
|
|
26
|
+
// Call type configuration
|
|
27
|
+
const CALL_TYPE_CONFIG = {
|
|
28
|
+
[CallTypeName.EndpointQuoteCall]: { param: LzTypeName.EndpointQuoteParam, result: LzTypeName.MessagingFee },
|
|
29
|
+
[CallTypeName.EndpointSendCall]: { param: LzTypeName.EndpointSendParam, result: LzTypeName.MessagingReceipt },
|
|
30
|
+
[CallTypeName.MessageLibQuoteCall]: { param: LzTypeName.MessageLibQuoteParam, result: LzTypeName.MessagingFee },
|
|
31
|
+
[CallTypeName.MessageLibSendCall]: {
|
|
32
|
+
param: LzTypeName.MessageLibSendParam,
|
|
33
|
+
result: LzTypeName.MessageLibSendResult,
|
|
34
|
+
},
|
|
35
|
+
[CallTypeName.MessageLibSetConfigCall]: { param: LzTypeName.MessageLibSetConfigParam, result: LzTypeName.CallVoid },
|
|
36
|
+
[CallTypeName.EndpointLzReceiveCall]: { param: LzTypeName.EndpointLzReceiveParam, result: LzTypeName.CallVoid },
|
|
37
|
+
[CallTypeName.EndpointLzComposeCall]: { param: LzTypeName.EndpointLzComposeParam, result: LzTypeName.CallVoid },
|
|
38
|
+
} as const
|
|
39
|
+
|
|
40
|
+
export function getTypeName(moduleManager: ModuleManager, type: LzTypeName | CallTypeName): string {
|
|
41
|
+
// Handle simple types
|
|
42
|
+
if (type in TYPE_CONFIG) {
|
|
43
|
+
const config = TYPE_CONFIG[type as keyof typeof TYPE_CONFIG]
|
|
44
|
+
const { packageId } = moduleManager.getModule<{ packageId: string }>(config.pkg)
|
|
45
|
+
return buildTypeName(packageId, config.module, config.type)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Handle Call types
|
|
49
|
+
if (type in CALL_TYPE_CONFIG) {
|
|
50
|
+
const callConfig = CALL_TYPE_CONFIG[type as keyof typeof CALL_TYPE_CONFIG]
|
|
51
|
+
const paramType = getTypeName(moduleManager, callConfig.param)
|
|
52
|
+
const resultType = getTypeName(moduleManager, callConfig.result)
|
|
53
|
+
return buildCallTypeName(moduleManager.getCall().packageId, paramType, resultType)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
throw new Error(`Unknown type name: ${JSON.stringify(type)}`)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Normalizes a Iota package ID with configurable formatting options
|
|
61
|
+
* @param packageId - The package ID to normalize (with or without 0x prefix)
|
|
62
|
+
* @param includePrefix - Whether to include the '0x' prefix in the result (default: false)
|
|
63
|
+
* @param trimLeadingZeros - Whether to remove leading zeros (default: true)
|
|
64
|
+
* @returns The normalized package ID
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* normalizeIotaPackageId('0x0001abc', false, true) // '1abc'
|
|
68
|
+
* normalizeIotaPackageId('0x0001abc', true, true) // '0x1abc'
|
|
69
|
+
* normalizeIotaPackageId('0x0001abc', true, false) // '0x0001abc'
|
|
70
|
+
*/
|
|
71
|
+
export function normalizeIotaPackageId(packageId: string, includePrefix = false, trimLeadingZeros = false): string {
|
|
72
|
+
// Remove 0x prefix if present
|
|
73
|
+
let normalized = packageId.startsWith('0x') ? packageId.slice(2) : packageId
|
|
74
|
+
|
|
75
|
+
// Trim leading zeros if requested
|
|
76
|
+
if (trimLeadingZeros) {
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
78
|
+
normalized = normalized.replace(/^0+/, '') || '0'
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Add prefix back if requested
|
|
82
|
+
return includePrefix ? `0x${normalized}` : normalized
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function callId(moduleManager: ModuleManager, type: CallTypeName): string {
|
|
86
|
+
return sha3.keccak_256(Buffer.from(getTypeName(moduleManager, type)))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// === Internal Functions ===
|
|
90
|
+
|
|
91
|
+
// Helper function: build basic type name
|
|
92
|
+
function buildTypeName(packageId: string, module: string, type: string): string {
|
|
93
|
+
return `${normalizeIotaPackageId(packageId)}::${module}::${type}`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Helper function: build Call type name
|
|
97
|
+
function buildCallTypeName(packageId: string, paramType: string, resultType: string): string {
|
|
98
|
+
return `${normalizeIotaPackageId(packageId)}::call::Call<${paramType},${resultType}>`
|
|
99
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { IotaClient } from '@iota/iota-sdk/client'
|
|
2
|
+
|
|
3
|
+
import { MoveCallObjectFetcher } from './move-call-object-fetcher'
|
|
4
|
+
import { IPTBValidator, ObjectFetchOptions } from './ptb-validator'
|
|
5
|
+
import { MAX_BATCH_SIZE, MoveCall } from '../types'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validates move calls using multiple validators with a single object fetch
|
|
9
|
+
* @param client - IotaClient instance
|
|
10
|
+
* @param moveCalls - Array of move calls to validate
|
|
11
|
+
* @param validators - Array of validators to run
|
|
12
|
+
* @param options - Options for what object data to fetch
|
|
13
|
+
* @param batchSize - Batch size for object fetching
|
|
14
|
+
*/
|
|
15
|
+
export async function validateWithDetails(
|
|
16
|
+
client: IotaClient,
|
|
17
|
+
moveCalls: MoveCall[],
|
|
18
|
+
validators: IPTBValidator[],
|
|
19
|
+
sender?: string,
|
|
20
|
+
userOptions: ObjectFetchOptions = {},
|
|
21
|
+
batchSize: number = MAX_BATCH_SIZE
|
|
22
|
+
): Promise<void> {
|
|
23
|
+
if (validators.length === 0) {
|
|
24
|
+
return // No validators to run
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Default to fetching all common options, user can override
|
|
28
|
+
const defaultOptions: ObjectFetchOptions = {
|
|
29
|
+
showOwner: true,
|
|
30
|
+
showType: true,
|
|
31
|
+
showContent: false,
|
|
32
|
+
showBcs: false,
|
|
33
|
+
showDisplay: false,
|
|
34
|
+
showStorageRebate: false,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Merge user options with defaults (user options take precedence)
|
|
38
|
+
const finalOptions = { ...defaultOptions, ...userOptions }
|
|
39
|
+
|
|
40
|
+
// Fetch object details once
|
|
41
|
+
const objectFetcher = new MoveCallObjectFetcher(client, batchSize)
|
|
42
|
+
const moveCallsWithDetails = await objectFetcher.fetchObjectDetails(moveCalls, finalOptions)
|
|
43
|
+
// Run all validators with the same object details
|
|
44
|
+
for (const validator of validators) {
|
|
45
|
+
const result = validator.validate(moveCallsWithDetails, sender)
|
|
46
|
+
if (result instanceof Promise) {
|
|
47
|
+
await result
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|