|
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
|
} from '../core/modules/impl/LexicographicalInteractionsSorter';
|
|
|
|
} from '../core/modules/impl/LexicographicalInteractionsSorter';
|
|
|
|
import { InteractionsSorter } from '../core/modules/InteractionsSorter';
|
|
|
|
import { InteractionsSorter } from '../core/modules/InteractionsSorter';
|
|
|
|
import { DefaultEvaluationOptions, EvalStateResult, EvaluationOptions } from '../core/modules/StateEvaluator';
|
|
|
|
import { DefaultEvaluationOptions, EvalStateResult, EvaluationOptions } from '../core/modules/StateEvaluator';
|
|
|
|
import { WARP_TAGS } from '../core/KnownTags';
|
|
|
|
import { SMART_WEAVE_TAGS, WARP_TAGS } from '../core/KnownTags';
|
|
|
|
import { Warp } from '../core/Warp';
|
|
|
|
import { Warp } from '../core/Warp';
|
|
|
|
import { createDummyTx, createInteractionTagsList, createInteractionTx } from '../legacy/create-interaction-tx';
|
|
|
|
import { createDummyTx, createInteractionTagsList, createInteractionTx } from '../legacy/create-interaction-tx';
|
|
|
|
import { GQLNodeInterface } from '../legacy/gqlResult';
|
|
|
|
import { GQLNodeInterface } from '../legacy/gqlResult';
|
|
|
|
@@ -24,7 +24,7 @@ import { Benchmark } from '../logging/Benchmark';
|
|
|
|
import { LoggerFactory } from '../logging/LoggerFactory';
|
|
|
|
import { LoggerFactory } from '../logging/LoggerFactory';
|
|
|
|
import { Evolve } from '../plugins/Evolve';
|
|
|
|
import { Evolve } from '../plugins/Evolve';
|
|
|
|
import { ArweaveWrapper } from '../utils/ArweaveWrapper';
|
|
|
|
import { ArweaveWrapper } from '../utils/ArweaveWrapper';
|
|
|
|
import { getJsonResponse, isBrowser, sleep, stripTrailingSlash } from '../utils/utils';
|
|
|
|
import { getJsonResponse, isBrowser, isTxIdValid, sleep, stripTrailingSlash } from '../utils/utils';
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
BenchmarkStats,
|
|
|
|
BenchmarkStats,
|
|
|
|
Contract,
|
|
|
|
Contract,
|
|
|
|
@@ -46,6 +46,15 @@ import { Buffer, Crypto } from 'warp-isomorphic';
|
|
|
|
import { VrfPluginFunctions } from '../core/WarpPlugin';
|
|
|
|
import { VrfPluginFunctions } from '../core/WarpPlugin';
|
|
|
|
import { createData, DataItem, Signer, tagsExceedLimit } from 'warp-arbundles';
|
|
|
|
import { createData, DataItem, Signer, tagsExceedLimit } from 'warp-arbundles';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
interface InteractionManifestData {
|
|
|
|
|
|
|
|
[path: string]: string;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
interface InteractionDataField<Input> {
|
|
|
|
|
|
|
|
input?: Input;
|
|
|
|
|
|
|
|
manifest?: InteractionManifestData;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* An implementation of {@link Contract} that is backwards compatible with current style
|
|
|
|
* An implementation of {@link Contract} that is backwards compatible with current style
|
|
|
|
* of writing SW contracts (ie. using the "handle" function).
|
|
|
|
* of writing SW contracts (ie. using the "handle" function).
|
|
|
|
@@ -76,6 +85,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
|
|
|
private _children: HandlerBasedContract<unknown>[] = [];
|
|
|
|
private _children: HandlerBasedContract<unknown>[] = [];
|
|
|
|
private _interactionState;
|
|
|
|
private _interactionState;
|
|
|
|
private _dreStates = new Map<string, SortKeyCacheResult<EvalStateResult<State>>>();
|
|
|
|
private _dreStates = new Map<string, SortKeyCacheResult<EvalStateResult<State>>>();
|
|
|
|
|
|
|
|
private maxInteractionDataItemSizeBytes: number;
|
|
|
|
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
constructor(
|
|
|
|
private readonly _contractTxId: string,
|
|
|
|
private readonly _contractTxId: string,
|
|
|
|
@@ -332,6 +342,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
|
|
|
const effectiveVrf = options?.vrf === true;
|
|
|
|
const effectiveVrf = options?.vrf === true;
|
|
|
|
const effectiveDisableBundling = options?.disableBundling === true;
|
|
|
|
const effectiveDisableBundling = options?.disableBundling === true;
|
|
|
|
const effectiveReward = options?.reward;
|
|
|
|
const effectiveReward = options?.reward;
|
|
|
|
|
|
|
|
const effectiveManifestData = options?.manifestData;
|
|
|
|
|
|
|
|
|
|
|
|
const bundleInteraction = interactionsLoader.type() == 'warp' && !effectiveDisableBundling;
|
|
|
|
const bundleInteraction = interactionsLoader.type() == 'warp' && !effectiveDisableBundling;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -358,7 +369,8 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
|
|
|
return await this.bundleInteraction(input, {
|
|
|
|
return await this.bundleInteraction(input, {
|
|
|
|
tags: effectiveTags,
|
|
|
|
tags: effectiveTags,
|
|
|
|
strict: effectiveStrict,
|
|
|
|
strict: effectiveStrict,
|
|
|
|
vrf: effectiveVrf
|
|
|
|
vrf: effectiveVrf,
|
|
|
|
|
|
|
|
manifestData: effectiveManifestData
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
const interactionTx = await this.createInteraction(
|
|
|
|
const interactionTx = await this.createInteraction(
|
|
|
|
@@ -398,16 +410,25 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
|
|
|
tags: Tags;
|
|
|
|
tags: Tags;
|
|
|
|
strict: boolean;
|
|
|
|
strict: boolean;
|
|
|
|
vrf: boolean;
|
|
|
|
vrf: boolean;
|
|
|
|
|
|
|
|
manifestData: InteractionManifestData;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
): Promise<WriteInteractionResponse | null> {
|
|
|
|
): Promise<WriteInteractionResponse | null> {
|
|
|
|
this.logger.info('Bundle interaction input', input);
|
|
|
|
this.logger.info('Bundle interaction input', input);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!this.maxInteractionDataItemSizeBytes) {
|
|
|
|
|
|
|
|
const response = fetch(`${stripTrailingSlash(this.warp.gwUrl())}`);
|
|
|
|
|
|
|
|
this.maxInteractionDataItemSizeBytes = (
|
|
|
|
|
|
|
|
await getJsonResponse<{ maxInteractionDataItemSizeBytes: number }>(response)
|
|
|
|
|
|
|
|
).maxInteractionDataItemSizeBytes;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const interactionDataItem = await this.createInteractionDataItem(
|
|
|
|
const interactionDataItem = await this.createInteractionDataItem(
|
|
|
|
input,
|
|
|
|
input,
|
|
|
|
options.tags,
|
|
|
|
options.tags,
|
|
|
|
emptyTransfer,
|
|
|
|
emptyTransfer,
|
|
|
|
options.strict,
|
|
|
|
options.strict,
|
|
|
|
options.vrf
|
|
|
|
options.vrf,
|
|
|
|
|
|
|
|
options.manifestData
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const response = this._warpFetchWrapper.fetch(
|
|
|
|
const response = this._warpFetchWrapper.fetch(
|
|
|
|
@@ -436,7 +457,8 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
|
|
|
tags: Tags,
|
|
|
|
tags: Tags,
|
|
|
|
transfer: ArTransfer,
|
|
|
|
transfer: ArTransfer,
|
|
|
|
strict: boolean,
|
|
|
|
strict: boolean,
|
|
|
|
vrf = false
|
|
|
|
vrf = false,
|
|
|
|
|
|
|
|
manifestData: InteractionManifestData
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
if (this._evaluationOptions.internalWrites) {
|
|
|
|
if (this._evaluationOptions.internalWrites) {
|
|
|
|
// it modifies tags
|
|
|
|
// it modifies tags
|
|
|
|
@@ -447,18 +469,33 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
|
|
|
tags.push(new Tag(WARP_TAGS.REQUEST_VRF, 'true'));
|
|
|
|
tags.push(new Tag(WARP_TAGS.REQUEST_VRF, 'true'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const interactionTags = createInteractionTagsList(
|
|
|
|
let interactionTags = createInteractionTagsList(
|
|
|
|
this._contractTxId,
|
|
|
|
this._contractTxId,
|
|
|
|
input,
|
|
|
|
input,
|
|
|
|
this.warp.environment === 'testnet',
|
|
|
|
this.warp.environment === 'testnet',
|
|
|
|
tags
|
|
|
|
tags
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let data: InteractionDataField<Input> | string;
|
|
|
|
if (tagsExceedLimit(interactionTags)) {
|
|
|
|
if (tagsExceedLimit(interactionTags)) {
|
|
|
|
throw new Error(`Interaction tags exceed limit of 4096 bytes.`);
|
|
|
|
interactionTags = [
|
|
|
|
|
|
|
|
...interactionTags.filter((t) => t.name != SMART_WEAVE_TAGS.INPUT && t.name != WARP_TAGS.INPUT_FORMAT),
|
|
|
|
|
|
|
|
new Tag(WARP_TAGS.INPUT_FORMAT, 'data')
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
data = {
|
|
|
|
|
|
|
|
input
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const data = Math.random().toString().slice(-4);
|
|
|
|
if (manifestData) {
|
|
|
|
|
|
|
|
data = {
|
|
|
|
|
|
|
|
...(data as InteractionData<Input>),
|
|
|
|
|
|
|
|
manifest: this.createManifest(manifestData)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data = data ? JSON.stringify(data) : Math.random().toString().slice(-4);
|
|
|
|
|
|
|
|
|
|
|
|
const bundlerSigner = this._signature.bundlerSigner;
|
|
|
|
const bundlerSigner = this._signature.bundlerSigner;
|
|
|
|
|
|
|
|
|
|
|
|
if (!bundlerSigner) {
|
|
|
|
if (!bundlerSigner) {
|
|
|
|
@@ -475,6 +512,14 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
|
|
|
await interactionDataItem.sign(bundlerSigner);
|
|
|
|
await interactionDataItem.sign(bundlerSigner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (interactionDataItem.getRaw().length > this.maxInteractionDataItemSizeBytes) {
|
|
|
|
|
|
|
|
throw new Error(
|
|
|
|
|
|
|
|
`Interaction data item size: ${interactionDataItem.getRaw().length} exceeds maximum interactions size limit: ${
|
|
|
|
|
|
|
|
this.maxInteractionDataItemSizeBytes
|
|
|
|
|
|
|
|
}.`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!this._evaluationOptions.internalWrites && strict) {
|
|
|
|
if (!this._evaluationOptions.internalWrites && strict) {
|
|
|
|
await this.checkInteractionInStrictMode(interactionDataItem.owner, input, tags, transfer, strict, vrf);
|
|
|
|
await this.checkInteractionInStrictMode(interactionDataItem.owner, input, tags, transfer, strict, vrf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -1142,4 +1187,22 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this._children = [];
|
|
|
|
this._children = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private createManifest(manifestData: InteractionManifestData) {
|
|
|
|
|
|
|
|
const paths = {};
|
|
|
|
|
|
|
|
Object.keys(manifestData).forEach((m) => {
|
|
|
|
|
|
|
|
const id = manifestData[m];
|
|
|
|
|
|
|
|
if (typeof m != 'string') {
|
|
|
|
|
|
|
|
throw new Error(`Incorrect manifest data. Manifest key should be of type 'string'`);
|
|
|
|
|
|
|
|
} else if (typeof id != 'string') {
|
|
|
|
|
|
|
|
throw new Error(`Incorrect manifest data. Manifest value should be of type 'string'`);
|
|
|
|
|
|
|
|
} else if (!isTxIdValid(id)) {
|
|
|
|
|
|
|
|
throw new Error(`Incorrect manifest data. Transaction id: ${id} is not valid.`);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paths[m] = manifestData[m];
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return paths;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|