Skip to content

Commit ce22f84

Browse files
authored
refactor(TS): general abi usage (#214)
* base, working for wasi exec * working TS impl + build-service fuel set fix * cleanup * nit
1 parent 83d171f commit ce22f84

File tree

6 files changed

+86
-21
lines changed

6 files changed

+86
-21
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,11 @@ WASI_BUILD_DIR=components/evm-price-oracle make wasi-build
177177
How to test the component locally for business logic validation before on-chain deployment. An ID of 1 for the oracle component is Bitcoin.
178178
179179
```bash
180-
# Rust components
180+
# Rust & Typescript components
181181
INPUT_DATA="1" COMPONENT_FILENAME=evm_price_oracle.wasm make wasi-exec
182+
INPUT_DATA="1" COMPONENT_FILENAME=js_evm_price_oracle.wasm make wasi-exec
182183
183-
# Golang / Typescript
184+
# Golang
184185
INPUT_DATA="1" COMPONENT_FILENAME=golang_evm_price_oracle.wasm make wasi-exec-fixed
185186
```
186187
@@ -277,11 +278,10 @@ bash ./script/deploy-script.sh
277278
Anyone can now call the [trigger contract](./src/contracts/WavsTrigger.sol) which emits the trigger event WAVS is watching for from the previous step. WAVS then calls the service and saves the result on-chain.
278279
279280
```bash
280-
# Request BTC from CMC
281-
# rust:
281+
# Rust & Typescript - request BTC from CMC
282282
export INPUT_DATA=`cast abi-encode "addTrigger(string)" "1"`
283283
284-
# Golang & Typescript uses the raw value
284+
# Golang uses the raw value
285285
# export INPUT_DATA="1"
286286
287287
# Get the trigger address from previous Deploy forge script

components/js-evm-price-oracle/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ WASI_BUILD_DIR=js-evm-price-oracle make wasi-build
3939
Run the component with the `wasi-exec` command in the root of the repo
4040

4141
```bash docci-output-contains="LTC"
42-
COMPONENT_FILENAME=js_evm_price_oracle.wasm INPUT_DATA=2 make wasi-exec-fixed
42+
COMPONENT_FILENAME=js_evm_price_oracle.wasm INPUT_DATA=2 make wasi-exec
4343
```
4444

4545
---

components/js-evm-price-oracle/index.ts

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { TriggerAction, WasmResponse } from "./out/wavs:worker@0.4.0";
1+
import { TriggerAction, WasmResponse, } from "./out/wavs:worker@0.4.0";
2+
import { TriggerSource, TriggerSourceManual } from "./out/interfaces/wavs-worker-layer-types";
23
import { decodeTriggerEvent, encodeOutput, Destination } from "./trigger";
4+
import { AbiCoder } from "ethers";
35

46
async function run(triggerAction: TriggerAction): Promise<WasmResponse> {
57
let event = decodeTriggerEvent(triggerAction.data);
68
let triggerId = event[0].triggerId;
79

8-
let result = await compute(event[0].data);
9-
10-
10+
let num = processInput(event[0].data, triggerAction.config.triggerSource);
11+
let result = await compute(num);
1112

1213
switch (event[1]) {
1314
case Destination.Cli:
@@ -29,15 +30,56 @@ async function run(triggerAction: TriggerAction): Promise<WasmResponse> {
2930
);
3031
}
3132

32-
async function compute(input: Uint8Array): Promise<Uint8Array> {
33-
const num = new TextDecoder().decode(input);
34-
35-
const priceFeed = await fetchCryptoPrice(parseInt(num));
33+
async function compute(num: number): Promise<Uint8Array> {
34+
const priceFeed = await fetchCryptoPrice(num);
3635
const priceJson = priceFeedToJson(priceFeed);
3736

3837
return new TextEncoder().encode(priceJson);
3938
}
4039

40+
function processInput(input: Uint8Array, triggerSource: { tag: string }): number {
41+
// Prepare the input data based on trigger type
42+
const processedInput = prepareInputData(input, triggerSource.tag);
43+
44+
// Single ABI decoding step
45+
const abiCoder = new AbiCoder();
46+
const res = abiCoder.decode(["string"], processedInput);
47+
const decodedString = res[0] as string;
48+
49+
console.log("Decoded input:", decodedString, "triggerSource.tag:", triggerSource.tag);
50+
51+
// Validate the decoded string is a valid number
52+
const num = decodedString.trim();
53+
if (isNaN(parseInt(num))) {
54+
throw new Error(`Input is not a valid number: ${num}`);
55+
}
56+
57+
return parseInt(num); // Return the validated number
58+
}
59+
60+
61+
function prepareInputData(input: Uint8Array, triggerTag: string): Uint8Array {
62+
if (triggerTag === "manual") {
63+
return input; // Use input directly for manual triggers
64+
}
65+
66+
// For evm-contract-event: handle potential hex string conversion
67+
try {
68+
const inputStr = new TextDecoder().decode(input);
69+
if (!inputStr.startsWith("0x")) {
70+
throw new Error("Input is not a valid hex string: " + inputStr);
71+
}
72+
73+
// Convert hex string to bytes
74+
const hexString = inputStr.slice(2); // Remove "0x" prefix
75+
return new Uint8Array(
76+
hexString.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16))
77+
);
78+
} catch {
79+
return input; // If UTF-8 decode fails, assume it's already binary
80+
}
81+
}
82+
4183
// ======================== CMC ========================
4284

4385
// Define the types for the CMC API response

script/build-service.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ eval "$BASE_CMD workflow component --id ${WORKFLOW_ID} permissions --http-hosts
7373
eval "$BASE_CMD workflow component --id ${WORKFLOW_ID} time-limit --seconds 30" > /dev/null
7474
eval "$BASE_CMD workflow component --id ${WORKFLOW_ID} env --values WAVS_ENV_SOME_SECRET" > /dev/null
7575
eval "$BASE_CMD workflow component --id ${WORKFLOW_ID} config --values 'key=value,key2=value2'" > /dev/null
76+
eval "$BASE_CMD workflow component --id ${WORKFLOW_ID} fuel-limit --fuel ${FUEL_LIMIT}" > /dev/null
7677

7778
eval "$BASE_CMD manager set-evm --chain-name ${SUBMIT_CHAIN} --address `cast --to-checksum ${WAVS_SERVICE_MANAGER_ADDRESS}`" > /dev/null
7879
eval "$BASE_CMD validate" > /dev/null

script/deploy-script.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ if git status --porcelain | grep -q "^.* components/"; then
1212
fi
1313

1414
### === Deploy Eigenlayer ===
15+
# if RPC_URL is not set, use default by calling command
16+
if [ -z "$RPC_URL" ]; then
17+
export RPC_URL=$(bash ./script/get-rpc-url.sh)
18+
fi
19+
if [ -z "$AGGREGATOR_URL" ]; then
20+
export AGGREGATOR_URL=http://127.0.0.1:8001
21+
fi
1522

1623
# local: create deployer & auto fund. testnet: create & iterate check balance
1724
bash ./script/create-deployer.sh

src/contracts/WavsTrigger.sol

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ contract SimpleTrigger is ISimpleTrigger {
1010
/// @inheritdoc ISimpleTrigger
1111
mapping(TriggerId _triggerId => Trigger _trigger) public triggersById;
1212
/// @notice See ISimpleTrigger.triggerIdsByCreator
13-
mapping(address _creator => TriggerId[] _triggerIds) internal _triggerIdsByCreator;
13+
mapping(address _creator => TriggerId[] _triggerIds)
14+
internal _triggerIdsByCreator;
1415

1516
/// @inheritdoc ISimpleTrigger
1617
function addTrigger(string memory _data) external {
@@ -19,26 +20,40 @@ contract SimpleTrigger is ISimpleTrigger {
1920
TriggerId _triggerId = nextTriggerId;
2021

2122
// Create the trigger
22-
Trigger memory _trigger = Trigger({creator: msg.sender, data: bytes(_data)});
23+
Trigger memory _trigger = Trigger({
24+
creator: msg.sender,
25+
data: bytes(_data)
26+
});
2327

2428
// Update storages
2529
triggersById[_triggerId] = _trigger;
2630
_triggerIdsByCreator[msg.sender].push(_triggerId);
2731

28-
TriggerInfo memory _triggerInfo =
29-
TriggerInfo({triggerId: _triggerId, creator: _trigger.creator, data: _trigger.data});
32+
TriggerInfo memory _triggerInfo = TriggerInfo({
33+
triggerId: _triggerId,
34+
creator: _trigger.creator,
35+
data: _trigger.data
36+
});
3037

3138
emit NewTrigger(abi.encode(_triggerInfo));
3239
}
3340

3441
/// @inheritdoc ISimpleTrigger
35-
function getTrigger(TriggerId triggerId) external view override returns (TriggerInfo memory _triggerInfo) {
42+
function getTrigger(
43+
TriggerId triggerId
44+
) external view override returns (TriggerInfo memory _triggerInfo) {
3645
Trigger storage _trigger = triggersById[triggerId];
37-
_triggerInfo = TriggerInfo({triggerId: triggerId, creator: _trigger.creator, data: _trigger.data});
46+
_triggerInfo = TriggerInfo({
47+
triggerId: triggerId,
48+
creator: _trigger.creator,
49+
data: _trigger.data
50+
});
3851
}
3952

4053
/// @inheritdoc ISimpleTrigger
41-
function triggerIdsByCreator(address _creator) external view returns (TriggerId[] memory _triggerIds) {
54+
function triggerIdsByCreator(
55+
address _creator
56+
) external view returns (TriggerId[] memory _triggerIds) {
4257
_triggerIds = _triggerIdsByCreator[_creator];
4358
}
4459
}

0 commit comments

Comments
 (0)