Skip to content

Commit

Permalink
use manifest to contract
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelmanzanera committed Sep 25, 2024
1 parent 8434670 commit c2e9338
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 80 deletions.
7 changes: 2 additions & 5 deletions example/transactionBuilder/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,14 +249,11 @@ let namedParams = [];

window.onChangeRecipient = async () => {
const address = document.querySelector("#recipient").value;
const contractCode = await archethic.network.getContractCode(address);
if (contractCode == "") {
return;
}
const contractContext = await archethic.network.getContractCode(address);

document.querySelector("#namedActionsContainer").style.display = "block";

const actions = await Contract.extractActionsFromContract(contractCode);
const actions = await Contract.extractActionsFromContract(contractContext);
actions.forEach((action) => {
const option = document.createElement("option");
option.text = action.name;
Expand Down
4 changes: 2 additions & 2 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,9 @@ export async function getContractCode(address: string | Uint8Array, endpoint: st
.then(handleResponse)
.then((res): string => {
if (res.errors || res.data == null) {
return "";
throw new Error("No contract at this address")
} else {
return res.data.lastTransaction.data.code;
return res.data.lastTransaction.data.code
}
});
}
Expand Down
90 changes: 48 additions & 42 deletions src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,65 @@ import { ContractAction } from "./types.js";
import { encryptSecret, deriveAddress } from "./crypto.js";
import { ExtendedTransactionBuilder } from "./transaction.js";
import Archethic from "./index.js";
import { hexToUint8Array, isHex } from "./utils.js";
import { isHex } from "./utils.js";

export async function extractActionsFromContract(code: string): Promise<ContractAction[]> {
let actions = [];
type CodeWithManifest = {
bytecode: string;
manifest: WasmManifest
}

if (isHex(code)) {
const wasmModule = await WebAssembly.instantiate(hexToUint8Array(code), {
"archethic/env": {
log: (offset: bigint, length: bigint) => {},
store_u8: (offset: bigint, data: bigint) => {},
load_u8: (offset: bigint): number => 0,
input_size: (): bigint => 0n,
alloc: (length: bigint): bigint => 0n,
set_output: (offset: bigint, length: bigint) => {},
set_error: (offset: bigint, length: bigint) => {}
},
// FIXME with JSON RPC like request
"archethic/IO": {
get_balance: (offset: bigint, length: bigint) => 0
}
});
type WasmManifest = {
abi: WasmABI
}

const reservedFunctions = ["spec", "init", "onUpgrade"];
for (let key in wasmModule.instance.exports) {
if (wasmModule.instance.exports[key] instanceof Function) {
if (!reservedFunctions.includes(key)) {
actions.push({ name: key, parameters: ["WASM JSON Input"] });
}
}
}
type WasmABI = {
functions: Record<string, WASMFunctionABI>
}

actions.push({ name: "upgrade", parameters: ['WASM JSON Input ( {"code": "wasm code as hex"})'] });
type WASMFunctionABI = {
type: string;
triggerType?: string;
name: string;
input: Record<string, any>
}

return actions;
export async function extractActionsFromContract(code: string): Promise<ContractAction[]> {
try {
const codeWithManifest: CodeWithManifest = JSON.parse(code)
const manifest = codeWithManifest.manifest
let actions: ContractAction[] = []
for (let name of Object.keys(manifest.abi.functions)) {
const functionABI = manifest.abi.functions[name]
if (functionABI.type == "action" && functionABI.triggerType == "transaction") {
actions.push({
name: name,
parameters: functionABI.input ? Object.keys(functionABI.input) : []
})
}
}
return actions
}
catch(e) {
let actions = [];

const regex = /actions\s+triggered_by:\s+transaction,\s+on:\s+([\w\s.,()]+?)\s+do/g;
const regex = /actions\s+triggered_by:\s+transaction,\s+on:\s+([\w\s.,()]+?)\s+do/g;

for (const match of code.matchAll(regex)) {
const fullAction = match[1];
for (const match of code.matchAll(regex)) {
const fullAction = match[1];

const regexActionName = /(\w+)\((.*?)\)/g;
for (const actionMatch of fullAction.matchAll(regexActionName)) {
const name = actionMatch[1];
const parameters = actionMatch[2] != "" ? actionMatch[2].split(",") : [];
actions.push({
name: name,
parameters: parameters
});
const regexActionName = /(\w+)\((.*?)\)/g;
for (const actionMatch of fullAction.matchAll(regexActionName)) {
const name = actionMatch[1];
const parameters = actionMatch[2] != "" ? actionMatch[2].split(",") : [];
actions.push({
name: name,
parameters: parameters
});
}
}
}

return actions;
return actions;
}
}

export function parseTypedArgument(input: any): any {
Expand Down
25 changes: 1 addition & 24 deletions src/transaction_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,36 +433,13 @@ export default class TransactionBuilder {
* JSON RPC API SEND_TRANSACTION
*/
async toNodeRPC(): Promise<TransactionRPC> {
async function asyncConcatUint8Arrays(uint8arrays: Uint8Array[]) {
const blob = new Blob(uint8arrays);
const buffer = await blob.arrayBuffer();
return new Uint8Array(buffer);
}

async function compress(str: Uint8Array): Promise<Uint8Array> {
// Convert the string to a byte stream.
const stream = new Blob([str]).stream();

// Create a compressed stream.
const compressedStream = stream.pipeThrough(new CompressionStream("deflate-raw"));

// Read all the bytes from this stream.
const chunks: Uint8Array[] = [];
//@ts-ignore
for await (const chunk of compressedStream) {
chunks.push(chunk);
}

return await asyncConcatUint8Arrays(chunks);
}

return {
version: this.version,
address: uint8ArrayToHex(this.address),
type: this.type,
data: {
content: new TextDecoder().decode(this.data.content),
code: uint8ArrayToHex(await compress(this.data.code)),
code: new TextDecoder().decode(this.data.code),
ownerships: this.data.ownerships.map(({ secret, authorizedPublicKeys }) => {
return {
secret: uint8ArrayToHex(secret),
Expand Down
7 changes: 0 additions & 7 deletions tests/transaction_builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,11 +603,4 @@ describe("Transaction builder", () => {
expect(txRPC.data.content).toStrictEqual("Hello world");
});
});

describe("toNodeRPC", () => {
it("should compress using zlib contract's code", async () => {
const tx = new TransactionBuilder("code").setCode("0061736d01000000015e1160017f017f60067f7f7f7f7f7f0060037f7f7f");
console.log(await tx.toNodeRPC());
});
});
});

0 comments on commit c2e9338

Please sign in to comment.