From 7c22ae8d67111e2655b5e808b842446a826571e3 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 14 Oct 2025 10:17:00 +0300 Subject: [PATCH 01/18] access list methods --- package-lock.json | 16 +-- package.json | 6 +- src/cli.ts | 71 ++++++++++ src/commands.ts | 176 +++++++++++++++++++++++- src/helpers.ts | 3 +- test/accessList.test.ts | 295 ++++++++++++++++++++++++++++++++++++++++ test/setup.test.ts | 12 +- 7 files changed, 564 insertions(+), 15 deletions(-) create mode 100644 test/accessList.test.ts diff --git a/package-lock.json b/package-lock.json index 614f079..6be5841 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,8 @@ "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", "@oceanprotocol/contracts": "^2.4.0", - "@oceanprotocol/ddo-js": "^0.1.3", - "@oceanprotocol/lib": "^5.0.0", + "@oceanprotocol/ddo-js": "^0.1.4", + "@oceanprotocol/lib": "^5.0.3", "commander": "^13.1.0", "cross-fetch": "^3.1.5", "crypto-js": "^4.1.1", @@ -3157,9 +3157,9 @@ "license": "Apache-2.0" }, "node_modules/@oceanprotocol/ddo-js": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@oceanprotocol/ddo-js/-/ddo-js-0.1.3.tgz", - "integrity": "sha512-CHZ0dZIM85xND6ckrVg5KIIXN5bYcNQV8udTISgCP3cTNOOlgnXdBPXELTKPg5h89qP8oEjofKC/kJjg+CJbng==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@oceanprotocol/ddo-js/-/ddo-js-0.1.4.tgz", + "integrity": "sha512-+9nOslJCYMiIldIQ8dixdSjBjrrlqzb9q+nRQXqn60ZIi45AoR4ajv1LdqPwScCmoeLZgMxiZsnUXq/suDSLNg==", "license": "Apache-2.0", "dependencies": { "@rdfjs/formats-common": "^3.1.0", @@ -3230,9 +3230,9 @@ } }, "node_modules/@oceanprotocol/lib": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-5.0.0.tgz", - "integrity": "sha512-gDnvsRivwMV2rlpeikmMXwVT73TK41FVd1cm6q55QMPUOpOsdW5K7gybFHbB+hwNd2FZuvpxwIHkH2PqKMCO1Q==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-5.0.3.tgz", + "integrity": "sha512-j+5QOs8JDSwiZvezHxSQVkQmL5ELG/isfCmGOgW22PbFT2xoMJUe2wWtAfhbDs/YgWsYP/mscwUUuwKOD2QcWA==", "license": "Apache-2.0", "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", diff --git a/package.json b/package.json index 43f2045..b14bd74 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "lint:fix": "eslint . --fix", "format": "prettier --parser typescript --ignore-path .gitignore --write '**/*.{js,jsx,ts,tsx}'", "cli": "npx tsx src/index.ts", - "test:system": "npm run mocha 'test/**/*.test.ts'", + "test:system": "npm run mocha 'test/**/accessList.test.ts'", "test": "npm run lint && npm run test:system", "mocha": "mocha --config=test/.mocharc.json --node-env=test --exit" }, @@ -46,8 +46,8 @@ "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", "@oceanprotocol/contracts": "^2.4.0", - "@oceanprotocol/ddo-js": "^0.1.3", - "@oceanprotocol/lib": "^5.0.0", + "@oceanprotocol/ddo-js": "^0.1.4", + "@oceanprotocol/lib": "^5.0.3", "commander": "^13.1.0", "cross-fetch": "^3.1.5", "crypto-js": "^4.1.1", diff --git a/src/cli.ts b/src/cli.ts index b00d7b0..0b5b3e1 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -490,5 +490,76 @@ export async function createCLI() { await commands.getAuthorizationsEscrow(token || options.token, payee || options.payee); }); + program + .command('createAccessList') + .description('Create a new access list contract') + .argument('', 'Name for the access list') + .argument('', 'Symbol for the access list') + .argument('[transferable]', 'Whether tokens are transferable (true/false)', 'false') + .argument('[initialUsers]', 'Comma-separated list of initial user addresses', '') + .option('-n, --name ', 'Name for the access list') + .option('-s, --symbol ', 'Symbol for the access list') + .option('-t, --transferable [transferable]', 'Whether tokens are transferable (true/false)', 'false') + .option('-u, --users [initialUsers]', 'Comma-separated list of initial user addresses', '') + .action(async (name, symbol, transferable, initialUsers, options) => { + const { signer, chainId } = await initializeSigner(); + const commands = new Commands(signer, chainId); + await commands.createAccessList([ + options.name || name, + options.symbol || symbol, + options.transferable || transferable, + options.users || initialUsers + ]); + }); + + program + .command('addToAccessList') + .description('Add user(s) to an access list') + .argument('', 'Address of the access list contract') + .argument('', 'Comma-separated list of user addresses to add') + .option('-a, --address ', 'Address of the access list contract') + .option('-u, --users ', 'Comma-separated list of user addresses to add') + .action(async (accessListAddress, users, options) => { + const { signer, chainId } = await initializeSigner(); + const commands = new Commands(signer, chainId); + await commands.addToAccessList([ + options.address || accessListAddress, + options.users || users + ]); + }); + + program + .command('checkAccessList') + .description('Check if user(s) are on an access list') + .argument('', 'Address of the access list contract') + .argument('', 'Comma-separated list of user addresses to check') + .option('-a, --address ', 'Address of the access list contract') + .option('-u, --users ', 'Comma-separated list of user addresses to check') + .action(async (accessListAddress, users, options) => { + const { signer, chainId } = await initializeSigner(); + const commands = new Commands(signer, chainId); + await commands.checkAccessList([ + options.address || accessListAddress, + options.users || users + ]); + }); + + program + .command('removeFromAccessList') + .description('Remove user(s) from an access list') + .argument('', 'Address of the access list contract') + .argument('', 'Comma-separated list of user addresses to remove') + .option('-a, --address ', 'Address of the access list contract') + .option('-u, --users ', 'Comma-separated list of user addresses to remove') + .action(async (accessListAddress, users, options) => { + const { signer, chainId } = await initializeSigner(); + const commands = new Commands(signer, chainId); + await commands.removeFromAccessList([ + options.address || accessListAddress, + options.users || users + ]); + }); + + return program; } \ No newline at end of file diff --git a/src/commands.ts b/src/commands.ts index 41807b8..40152b9 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -27,7 +27,9 @@ import { sendTx, unitsToAmount, EscrowContract, - getTokenDecimals + getTokenDecimals, + AccesslistFactory, + AccessListContract } from "@oceanprotocol/lib"; import { Asset } from '@oceanprotocol/ddo-js'; import { Signer, ethers, getAddress } from "ethers"; @@ -1454,4 +1456,176 @@ export class Commands { return authorizations; } + + public async createAccessList(args: string[]): Promise { + try { + const name = args[0]; + const symbol = args[1]; + const transferable = args[2] === 'true'; + const initialUsers = args[3] ? args[3].split(',').map(u => u.trim()) : []; + + if (!name || !symbol) { + console.error(chalk.red('Name and symbol are required')); + return; + } + + const config = await getConfigByChainId(Number(this.config.chainId)); + if (!config.AccessListFactory) { + console.error(chalk.red('Access list factory not found. Check local address.json file')); + return; + } + const accessListFactory = new AccesslistFactory( + config.AccessListFactory, + this.signer, + Number(this.config.chainId) + ); + + const owner = await this.signer.getAddress(); + const tokenURIs = initialUsers.map(() => 'https://oceanprotocol.com/nft/'); + + console.log(chalk.cyan('Creating new access list...')); + console.log(`Name: ${name}`); + console.log(`Symbol: ${symbol}`); + console.log(`Transferable: ${transferable}`); + console.log(`Owner: ${owner}`); + console.log(`Initial users: ${initialUsers.length > 0 ? initialUsers.join(', ') : 'none'}`); + + const accessListAddress = await accessListFactory.deployAccessListContract( + name, + symbol, + tokenURIs, + transferable, + owner, + initialUsers + ); + + console.log(chalk.green(`\nAccess list created successfully!`)); + console.log(chalk.green(`Contract address: ${accessListAddress}`)); + } catch (error) { + console.error(chalk.red('Error creating access list:'), error); + } + } + + public async addToAccessList(args: string[]): Promise { + try { + const accessListAddress = args[0]; + const users = args[1].split(',').map(u => u.trim()); + + if (!accessListAddress || users.length === 0) { + console.error(chalk.red('Access list address and at least one user are required')); + return; + } + + const accessList = new AccessListContract( + accessListAddress, + this.signer, + Number(this.config.chainId) + ); + + console.log(chalk.cyan(`Adding ${users.length} user(s) to access list...`)); + + if (users.length === 1) { + const tx = await accessList.mint(users[0], 'https://oceanprotocol.com/nft/'); + await tx.wait(); + console.log(chalk.green(`Successfully added user ${users[0]} to access list`)); + return; + } + + const tokenURIs = users.map(() => 'https://oceanprotocol.com/nft/'); + const tx = await accessList.batchMint(users, tokenURIs); + await tx.wait(); + console.log(chalk.green(`Successfully added ${users.length} users to access list:`)); + users.forEach(user => console.log(` - ${user}`)); + } catch (error) { + console.error(chalk.red('Error adding users to access list:'), error); + } + } + + + public async checkAccessList(args: string[]): Promise { + try { + const accessListAddress = args[0]; + const users = args[1].split(',').map(u => u.trim()); + + if (!accessListAddress || users.length === 0) { + console.error(chalk.red('Access list address and at least one user are required')); + return; + } + + const accessList = new AccessListContract( + accessListAddress, + this.signer, + Number(this.config.chainId) + ); + + console.log(chalk.cyan(`Checking access list for ${users.length} user(s)...\n`)); + + for (const user of users) { + const balance = await accessList.balance(user); + const hasAccess = Number(balance) > 0; + + if (hasAccess) { + console.log(chalk.green(`✓ ${user}: Has access (balance: ${balance})`)); + } else { + console.log(chalk.red(`✗ ${user}: No access`)); + } + } + } catch (error) { + console.error(chalk.red('Error checking access list:'), error); + } + } + + + public async removeFromAccessList(args: string[]): Promise { + try { + const accessListAddress = args[0]; + const users = args[1].split(',').map(u => u.trim()); + + if (!accessListAddress || users.length === 0) { + console.error(chalk.red('Access list address and at least one user address are required')); + return; + } + + const accessList = new AccessListContract( + accessListAddress, + this.signer, + Number(this.config.chainId) + ); + + console.log(chalk.cyan(`Removing ${users.length} user(s) from access list...`)); + for (const user of users) { + const balance = await accessList.balance(user); + + if (Number(balance) === 0) { + console.log(chalk.yellow(`⚠ User ${user} is not on the access list, skipping...`)); + continue; + } + + const balanceNum = Number(balance); + const contract = accessList.contract; + + let removedCount = 0; + for (let index = 0; index < balanceNum; index++) { + try { + const tokenId = await contract.tokenOfOwnerByIndex(user, index); + const tx = await accessList.burn(Number(tokenId)); + await tx.wait(); + + console.log(chalk.green(`✓ Successfully removed user ${user} (token ID: ${tokenId})`)); + removedCount++; + } catch (e: any) { + console.log(chalk.yellow(`⚠ Could not remove token at index ${index} for user ${user}: ${e.message}`)); + } + } + + if (removedCount === 0) { + console.log(chalk.yellow(`⚠ Could not remove any tokens for user ${user}`)); + } else if (removedCount < balanceNum) { + console.log(chalk.yellow(`⚠ Only removed ${removedCount} of ${balanceNum} tokens for user ${user}`)); + } + } + } catch (error) { + console.error(chalk.red('Error removing users from access list:'), error); + } + } } diff --git a/src/helpers.ts b/src/helpers.ts index 0d7647b..e42eb81 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -5,8 +5,7 @@ import * as path from "path"; import * as sapphire from '@oasisprotocol/sapphire-paratime'; import { Asset, DDO } from '@oceanprotocol/ddo-js'; import { - AccesslistFactory, - Aquarius, + AccesslistFactory, Aquarius, Nft, NftFactory, ProviderInstance, diff --git a/test/accessList.test.ts b/test/accessList.test.ts new file mode 100644 index 0000000..39780d2 --- /dev/null +++ b/test/accessList.test.ts @@ -0,0 +1,295 @@ +import { expect } from "chai"; +import { homedir } from 'os'; +import { runCommand } from "./util.js"; +import { getConfigByChainId } from "../src/helpers.js"; +import { JsonRpcProvider, ethers } from "ethers"; +import { AccessListContract, AccesslistFactory } from "@oceanprotocol/lib"; + +describe("Ocean CLI Access List", function () { + this.timeout(120000); + + let chainConfig: any; + let accessListAddress: string; + let owner: ethers.Wallet; + let testUser1: ethers.Wallet; + let testUser2: ethers.Wallet; + + before(async function () { + process.env.AVOID_LOOP_RUN = "true"; + process.env.PRIVATE_KEY = "0xc594c6e5def4bab63ac29eed19a134c130388f74f019bc74b8f4389df2837a58"; + process.env.RPC = "http://localhost:8545"; + process.env.NODE_URL = "http://localhost:8000"; + process.env.ADDRESS_FILE = `${homedir}/.ocean/ocean-contracts/artifacts/address.json`; + + chainConfig = await getConfigByChainId(8996); + + const provider = new JsonRpcProvider(process.env.RPC); + owner = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + testUser1 = new ethers.Wallet('0xef4b441145c1d0f3b4bc6d61d29f5c6e502359481152f869247c7a4244d45209', provider); + testUser2 = new ethers.Wallet('0x5d75837c166221195c8763c7f6fc5f6b8f0e8f43f9f4e0b0e7a3f7e2f9f4e3a1', provider); + }); + + describe("Create Access List", function () { + it("should create a new access list contract", async function () { + const name = "TestAccessList"; + const symbol = "TAL"; + const transferable = "false"; + + const output = await runCommand( + `npm run cli createAccessList ${name} ${symbol} ${transferable}` + ); + + expect(output).to.include("Access list created successfully"); + expect(output).to.include("Contract address:"); + + const addressMatch = output.match(/Contract address: (0x[a-fA-F0-9]{40})/); + if (addressMatch) { + accessListAddress = addressMatch[1]; + console.log(`Created access list at: ${accessListAddress}`); + } else { + throw new Error("Could not extract access list address from output"); + } + }); + + it("should create a new access list with initial users", async function () { + const name = "TestAccessListWithUsers"; + const symbol = "TALWU"; + const transferable = "false"; + const initialUsers = `${testUser1.address},${testUser2.address}`; + + const output = await runCommand( + `npm run cli createAccessList ${name} ${symbol} ${transferable} ${initialUsers}` + ); + + expect(output).to.include("Access list created successfully"); + expect(output).to.include("Contract address:"); + expect(output).to.include(`Initial users: ${testUser1.address}, ${testUser2.address}`); + }); + + it("should fail to create access list without required parameters", async function () { + try { + await runCommand(`npm run cli createAccessList`); + throw new Error("Should have thrown an error"); + } catch (error: any) { + expect(error.stderr || error.message).to.satisfy((msg: string) => + msg.includes("error: missing required argument") || + msg.includes("Name and symbol are required") + ); + } + }); + }); + + describe("Add Users to Access List", function () { + it("should add a single user to the access list", async function () { + const output = await runCommand( + `npm run cli addToAccessList ${accessListAddress} ${testUser1.address}` + ); + + expect(output).to.include(`Successfully added user ${testUser1.address}`); + }); + + it("should add multiple users to the access list", async function () { + const users = `${testUser2.address},${owner.address}`; + + const output = await runCommand( + `npm run cli addToAccessList ${accessListAddress} ${users}` + ); + + expect(output).to.include("Successfully added"); + expect(output).to.include("users to access list"); + }); + + it("should fail to add users without required parameters", async function () { + try { + await runCommand(`npm run cli addToAccessList ${accessListAddress}`); + throw new Error("Should have thrown an error"); + } catch (error: any) { + expect(error.stderr || error.message).to.satisfy((msg: string) => + msg.includes("error: missing required argument") || + msg.includes("at least one user are required") + ); + } + }); + }); + + describe("Check Users on Access List", function () { + it("should check if a single user is on the access list", async function () { + const output = await runCommand( + `npm run cli checkAccessList ${accessListAddress} ${testUser1.address}` + ); + + expect(output).to.include(testUser1.address); + expect(output).to.satisfy((msg: string) => + msg.includes("Has access") || msg.includes("No access") + ); + }); + + it("should check multiple users on the access list", async function () { + const users = `${testUser1.address},${testUser2.address}`; + + const output = await runCommand( + `npm run cli checkAccessList ${accessListAddress} ${users}` + ); + + expect(output).to.include(testUser1.address); + expect(output).to.include(testUser2.address); + }); + + it("should show 'Has access' for users on the list", async function () { + const output = await runCommand( + `npm run cli checkAccessList ${accessListAddress} ${testUser1.address}` + ); + + expect(output).to.include("Has access"); + }); + + it("should verify user access using direct contract call", async function () { + const accessList = new AccessListContract( + accessListAddress, + owner, + chainConfig.chainId + ); + + const balance = await accessList.balance(testUser1.address); + expect(Number(balance)).to.be.greaterThan(0); + }); + }); + + describe("Remove Users from Access List", function () { + it("should remove a user from the access list by address", async function () { + const output = await runCommand( + `npm run cli removeFromAccessList ${accessListAddress} ${testUser1.address}` + ); + + expect(output).to.include("Successfully removed user"); + expect(output).to.include(testUser1.address); + }); + + it("should remove multiple users by addresses", async function () { + await runCommand( + `npm run cli addToAccessList ${accessListAddress} ${testUser1.address}` + ); + + await runCommand( + `npm run cli addToAccessList ${accessListAddress} ${testUser2.address}` + ); + + const users = `${testUser1.address},${testUser2.address}`; + + const output = await runCommand( + `npm run cli removeFromAccessList ${accessListAddress} ${users}` + ); + + expect(output).to.include("Successfully removed user"); + }); + + it("should handle removing a user not on the access list", async function () { + const nonExistentUser = "0x0000000000000000000000000000000000000001"; + + const output = await runCommand( + `npm run cli removeFromAccessList ${accessListAddress} ${nonExistentUser}` + ); + + expect(output).to.include("not on the access list"); + }); + + it("should fail to remove with invalid address", async function () { + const invalidAddress = "invalid-address"; + + try { + await runCommand( + `npm run cli removeFromAccessList ${accessListAddress} ${invalidAddress}` + ); + } catch (error: any) { + expect(error.stderr || error.message).to.satisfy((msg: string) => + msg.includes("Error removing users") || + msg.includes("error") || + msg.includes("invalid address") + ); + } + }); + }); + + describe("Access List Factory", function () { + it("should verify access list is deployed via factory", async function () { + const factory = new AccesslistFactory( + chainConfig.AccessListFactory, + owner, + chainConfig.chainId + ); + + const isDeployed = await factory.isDeployed(accessListAddress); + expect(isDeployed).to.be.true; + }); + + it("should verify access list is soulbound", async function () { + const factory = new AccesslistFactory( + chainConfig.AccessListFactory, + owner, + chainConfig.chainId + ); + + const isSoulbound = await factory.isSoulbound(accessListAddress); + expect(isSoulbound).to.be.true; + }); + }); + + + describe("Edge Cases", function () { + it("should handle empty initial users list", async function () { + const output = await runCommand( + `npm run cli createAccessList EmptyList EL false ""` + ); + + expect(output).to.include("Access list created successfully"); + expect(output).to.include("Initial users: none"); + }); + + it("should fail with invalid address format", async function () { + try { + await runCommand( + `npm run cli checkAccessList ${accessListAddress} invalid-address` + ); + } catch (error: any) { + expect(error.stderr || error.message).to.satisfy((msg: string) => + msg.includes("Error checking access list") || + msg.includes("error") || + msg.includes("invalid address") + ); + } + }); + }); + + describe("E2E Workflow", function () { + it("should complete a full access list workflow", async function () { + const createOutput = await runCommand( + `npm run cli createAccessList WorkflowTest WT false` + ); + expect(createOutput).to.include("Access list created successfully"); + + const addressMatch = createOutput.match(/Contract address: (0x[a-fA-F0-9]{40})/); + const workflowAccessList = addressMatch ? addressMatch[1] : ""; + + const addOutput = await runCommand( + `npm run cli addToAccessList ${workflowAccessList} ${testUser1.address}` + ); + expect(addOutput).to.include("Successfully added"); + + const checkOutput = await runCommand( + `npm run cli checkAccessList ${workflowAccessList} ${testUser1.address}` + ); + expect(checkOutput).to.include("Has access"); + + const removeOutput = await runCommand( + `npm run cli removeFromAccessList ${workflowAccessList} ${testUser1.address}` + ); + expect(removeOutput).to.include("Successfully removed"); + + const finalCheckOutput = await runCommand( + `npm run cli checkAccessList ${workflowAccessList} ${testUser1.address}` + ); + expect(finalCheckOutput).to.include("No access"); + }); + }); +}); + diff --git a/test/setup.test.ts b/test/setup.test.ts index b1c7dc4..1137624 100644 --- a/test/setup.test.ts +++ b/test/setup.test.ts @@ -51,7 +51,17 @@ describe("Ocean CLI Setup", function() { expect(stdout).to.contain("Gets the existing compute environments"); expect(stdout).to.contain("computeStreamableLogs"); expect(stdout).to.contain("Gets the existing compute streamable logs"); - + expect(stdout).to.contain("createAccessList"); + expect(stdout).to.contain("Create a new access list contract"); + expect(stdout).to.contain("addToAccessList"); + expect(stdout).to.contain("Add user(s) to an access list"); + expect(stdout).to.contain("checkAccessList"); + expect(stdout).to.contain("Check if user(s) are on an access list"); + expect(stdout).to.contain("removeFromAccessList"); + expect(stdout).to.contain("Remove user(s) from an access list"); + expect(stdout).to.contain("getAccessListInfo"); + expect(stdout).to.contain("Get information about an access list"); + done(); } catch (assertionError) { done(assertionError); From 7f7ff295debfeb813c151792fc561409466d8633 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 14 Oct 2025 10:18:07 +0300 Subject: [PATCH 02/18] fix package json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b14bd74..841e646 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "lint:fix": "eslint . --fix", "format": "prettier --parser typescript --ignore-path .gitignore --write '**/*.{js,jsx,ts,tsx}'", "cli": "npx tsx src/index.ts", - "test:system": "npm run mocha 'test/**/accessList.test.ts'", + "test:system": "npm run mocha 'test/**/.test.ts'", "test": "npm run lint && npm run test:system", "mocha": "mocha --config=test/.mocharc.json --node-env=test --exit" }, From a59a25c24da764d47bfaf529638fdc2d0c0046e6 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 14 Oct 2025 10:18:45 +0300 Subject: [PATCH 03/18] revert package json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 841e646..856f933 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "lint:fix": "eslint . --fix", "format": "prettier --parser typescript --ignore-path .gitignore --write '**/*.{js,jsx,ts,tsx}'", "cli": "npx tsx src/index.ts", - "test:system": "npm run mocha 'test/**/.test.ts'", + "test:system": "npm run mocha 'test/**/*.test.ts'", "test": "npm run lint && npm run test:system", "mocha": "mocha --config=test/.mocharc.json --node-env=test --exit" }, From 54f117435cc33e7d1363676c0a70034a16610e2f Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 14 Oct 2025 13:55:35 +0300 Subject: [PATCH 04/18] bump contracts --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6be5841..20d58e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "Apache-2.0", "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", - "@oceanprotocol/contracts": "^2.4.0", + "@oceanprotocol/contracts": "^2.4.1", "@oceanprotocol/ddo-js": "^0.1.4", "@oceanprotocol/lib": "^5.0.3", "commander": "^13.1.0", @@ -3151,9 +3151,9 @@ } }, "node_modules/@oceanprotocol/contracts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-2.4.0.tgz", - "integrity": "sha512-OqDUBqQXPT68geLgGJDyH9Wsg1lE1V4ZS7aCJSfGdDWlMOBUAh/KxuaY46ga6WwWz8XVGTB+HZLGLQTYROo5tw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-2.4.1.tgz", + "integrity": "sha512-mOad2bCyOqYTp5oSiivH23shU/AyfEfp/beBl9zkSEhz7LagvFvDAIicELfHd0NaSVSwvTbM5NbMuOC0Wd5NSA==", "license": "Apache-2.0" }, "node_modules/@oceanprotocol/ddo-js": { diff --git a/package.json b/package.json index 856f933..40e8789 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ }, "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", - "@oceanprotocol/contracts": "^2.4.0", + "@oceanprotocol/contracts": "^2.4.1", "@oceanprotocol/ddo-js": "^0.1.4", "@oceanprotocol/lib": "^5.0.3", "commander": "^13.1.0", From 3f832fac0c655e7204311271995e2ddb9d537bda Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 10:06:56 +0300 Subject: [PATCH 05/18] try node branch --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 578b5cc..8cd8e2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,6 +66,9 @@ jobs: - name: Set ADDRESS_FILE run: echo "ADDRESS_FILE=${HOME}/.ocean/ocean-contracts/artifacts/address.json" >> $GITHUB_ENV + - name: Set up node env + run: | + echo "NODE_VERSION=pr-1073" >> $GITHUB_ENV - name: Checkout Barge uses: actions/checkout@v3 with: From 79bd4c1ed3e6d5276b05609325a2b6d6dd45fef9 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 11:09:02 +0300 Subject: [PATCH 06/18] fix escrow commands --- src/commands.ts | 2 +- test/paidComputeFlow.test.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 40152b9..53840e5 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -733,7 +733,7 @@ export class Commands { await new Promise(resolve => setTimeout(resolve, 3000)) const validationEscrow = await escrow.verifyFundsForEscrowPayment( paymentToken, - computeEnv.consumerAddress, + await this.signer.getAddress(), await unitsToAmount(this.signer, paymentToken, parsedProviderInitializeComputeJob.payment.amount), parsedProviderInitializeComputeJob.payment.amount.toString(), parsedProviderInitializeComputeJob.payment.minLockSeconds.toString(), diff --git a/test/paidComputeFlow.test.ts b/test/paidComputeFlow.test.ts index b53395b..eb8cb95 100644 --- a/test/paidComputeFlow.test.ts +++ b/test/paidComputeFlow.test.ts @@ -18,6 +18,7 @@ describe("Ocean CLI Paid Compute", function() { let resources: any; let computeJobId: string; let agreementId: string; + process.env.AVOID_LOOP_RUN = "true"; const getAddresses = () => { const data = JSON.parse( @@ -155,15 +156,15 @@ describe("Ocean CLI Paid Compute", function() { resources = [ { id: 'cpu', - amount: env.resources[0].max - env.resources[0].inUse - 1 + amount: 1 }, { id: 'ram', - amount: env.resources[1].max - env.resources[1].inUse - 1000 + amount: 1 }, { id: 'disk', - amount: 0 + amount: 1 } ] const paymentToken = getAddresses().Ocean From d11d1e5860ba2cdb9bc9592fbf0fe1955801a626 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 11:14:59 +0300 Subject: [PATCH 07/18] print logs --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cd8e2c..bc1c524 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,4 +139,4 @@ jobs: if: ${{ failure() }} run: | echo "========== Ocean Node Logs ==========" - tac ${{ github.workspace }}/ocean-node/ocean-node.log || echo "Log file not found" + docker logs ocean-node-1 2>&1 || echo "Ocean Node container logs not available" From d0a7d5db03fd68f3d1888f8da2ffeb9a45dd24a3 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 13:11:25 +0300 Subject: [PATCH 08/18] latest logs --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc1c524..8ee29cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,4 +139,4 @@ jobs: if: ${{ failure() }} run: | echo "========== Ocean Node Logs ==========" - docker logs ocean-node-1 2>&1 || echo "Ocean Node container logs not available" + docker logs --tail 1000 ocean-node-1 2>&1 | tac || echo "Ocean Node container logs not available" From f34df3084534a84f9113da99dffe9672e47cb914 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 13:37:32 +0300 Subject: [PATCH 09/18] fix compute command --- src/commands.ts | 65 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 53840e5..f5a3618 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -731,24 +731,57 @@ export class Commands { ) console.log("Verifying payment..."); await new Promise(resolve => setTimeout(resolve, 3000)) - const validationEscrow = await escrow.verifyFundsForEscrowPayment( + + const payerAddress = await this.signer.getAddress(); + const payeeAddress = computeEnv.consumerAddress; + + const authorizations = await escrow.getAuthorizations( paymentToken, - await this.signer.getAddress(), - await unitsToAmount(this.signer, paymentToken, parsedProviderInitializeComputeJob.payment.amount), - parsedProviderInitializeComputeJob.payment.amount.toString(), - parsedProviderInitializeComputeJob.payment.minLockSeconds.toString(), - '10' - ) - if (validationEscrow.isValid === false) { - console.error( - "Error starting compute job dataset DID " + - args[1] + - " and algorithm DID " + - args[2] + - " because escrow funds check failed: " - + validationEscrow.message + payerAddress, + payeeAddress + ); + + // If no authorization exists, create one + if (!authorizations || authorizations.length === 0) { + console.log(`Creating authorization for provider ${payeeAddress}...`); + const authorizeTx = await escrow.authorize( + getAddress(paymentToken), + getAddress(payeeAddress), + parsedProviderInitializeComputeJob.payment.amount.toString(), + parsedProviderInitializeComputeJob.payment.minLockSeconds.toString(), + '10' ); - return; + await authorizeTx.wait(); + console.log(`Successfully authorized provider ${payeeAddress}`); + } else { + console.log(`Provider ${payeeAddress} is already authorized`); + } + + // Check escrow balance and deposit if needed + const paymentAmount = await unitsToAmount(this.signer, paymentToken, parsedProviderInitializeComputeJob.payment.amount); + const escrowBalance = await escrow.getUserFunds(payerAddress, paymentToken); + const currentBalance = await unitsToAmount(this.signer, paymentToken, escrowBalance.available); + + console.log(`Current escrow balance: ${currentBalance}, Required: ${paymentAmount}`); + + if (Number(currentBalance) < Number(paymentAmount)) { + console.log(`Depositing ${paymentAmount} to escrow...`); + const depositSuccess = await this.depositToEscrow( + this.signer, + paymentToken, + paymentAmount, + Number((await this.signer.provider.getNetwork()).chainId) + ); + + if (!depositSuccess) { + console.error( + "Error starting compute job - escrow deposit failed for dataset DID " + + args[1] + + " and algorithm DID " + + args[2] + ); + return; + } } console.log("Starting compute job using provider: ", providerURI); From d50fbc1c4f0e91cdcfb331ae5807fbabeaea9b15 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 13:50:49 +0300 Subject: [PATCH 10/18] change PK --- test/paidComputeFlow.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/paidComputeFlow.test.ts b/test/paidComputeFlow.test.ts index eb8cb95..38591e2 100644 --- a/test/paidComputeFlow.test.ts +++ b/test/paidComputeFlow.test.ts @@ -38,10 +38,10 @@ describe("Ocean CLI Paid Compute", function() { throw new Error("Metadata file not found: " + metadataFile); } - process.env.PRIVATE_KEY = "0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc"; - // Using this account: 0x529043886F21D9bc1AE0feDb751e34265a246e47 - process.env.RPC = "http://127.0.0.1:8545"; - process.env.NODE_URL = "http://127.0.0.1:8001"; + process.env.PRIVATE_KEY = "0xc594c6e5def4bab63ac29eed19a134c130388f74f019bc74b8f4389df2837a58"; + // Using this account: 0xe2DD09d719Da89e5a3D0F2549c7E24566e947260 + process.env.RPC = "http://localhost:8545"; + process.env.NODE_URL = "http://localhost:8001"; process.env.ADDRESS_FILE = path.join(process.env.HOME || "", ".ocean/ocean-contracts/artifacts/address.json"); const output = await runCommand(`npm run cli publish ${metadataFile}`); From c614dbaed9e83ab2faccd4469bc6332c4b8922bb Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 14:26:13 +0300 Subject: [PATCH 11/18] use main branch --- .github/workflows/ci.yml | 3 --- test/paidComputeFlow.test.ts | 16 ++-------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ee29cc..eec1232 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,9 +66,6 @@ jobs: - name: Set ADDRESS_FILE run: echo "ADDRESS_FILE=${HOME}/.ocean/ocean-contracts/artifacts/address.json" >> $GITHUB_ENV - - name: Set up node env - run: | - echo "NODE_VERSION=pr-1073" >> $GITHUB_ENV - name: Checkout Barge uses: actions/checkout@v3 with: diff --git a/test/paidComputeFlow.test.ts b/test/paidComputeFlow.test.ts index 38591e2..f8326da 100644 --- a/test/paidComputeFlow.test.ts +++ b/test/paidComputeFlow.test.ts @@ -153,22 +153,10 @@ describe("Ocean CLI Paid Compute", function() { const env = computeEnvs[0]; expect(env).to.be.an('object').and.to.not.be.null.and.to.not.be.undefined; - resources = [ - { - id: 'cpu', - amount: 1 - }, - { - id: 'ram', - amount: 1 - }, - { - id: 'disk', - amount: 1 - } - ] + resources = [] const paymentToken = getAddresses().Ocean const output = await runCommand(`npm run cli -- startCompute ${computeDatasetDid} ${jsAlgoDid} ${computeEnvId} 900 ${paymentToken} '${JSON.stringify(resources)}' --accept true`); + console.log({ output: JSON.stringify(output, null, 2) }) const jobIdMatch = output.match(/JobID:\s*([^\s]+)/); const agreementIdMatch = output.match(/Agreement ID:\s*([^\s]+)/); From 29d4ae521328c0748fac2bf92fd7dc5fadfc6c16 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 14:47:37 +0300 Subject: [PATCH 12/18] try catch start compute job --- src/commands.ts | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index f5a3618..e67225b 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -813,23 +813,27 @@ export class Commands { metadataUri: await getMetadataURI(), }; - const computeJobs = await ProviderInstance.computeStart( - providerURI, - this.signer, - computeEnv.id, - assets, // assets[0] // only c2d v1, - algo, - supportedMaxJobDuration, - paymentToken, - JSON.parse(resources), - Number((await this.signer.provider.getNetwork()).chainId), - null, - null, - // additionalDatasets, only c2d v1 - output, - ); - - console.log("compute jobs: ", computeJobs); + let computeJobs = null; + try { + computeJobs = await ProviderInstance.computeStart( + providerURI, + this.signer, + computeEnv.id, + assets, // assets[0] // only c2d v1, + algo, + supportedMaxJobDuration, + paymentToken, + JSON.parse(resources), + Number((await this.signer.provider.getNetwork()).chainId), + null, + null, + // additionalDatasets, only c2d v1 + output + ); + } catch (error) { + console.error("Error while starting the compute job: ", error); + throw new Error("Error while starting the compute job"); + } if (computeJobs && computeJobs[0]) { const { jobId, payment } = computeJobs[0]; From 8e4c16e7919ba99ea9a7c2d4c47c47badfe1ffe4 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 14:57:56 +0300 Subject: [PATCH 13/18] log stderr --- test/util.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/test/util.ts b/test/util.ts index d2fb9d3..d29ca56 100644 --- a/test/util.ts +++ b/test/util.ts @@ -14,13 +14,14 @@ export const __dirname = dirname(__filename) export const projectRoot = path.resolve(__dirname, ".."); export const runCommand = async (command: string): Promise => { - console.log(`\n[CMD]: ${command}`); - try { - const { stdout } = await execPromise(command, { cwd: projectRoot }); - console.log(`[OUTPUT]:\n${stdout}`); - return stdout; - } catch (error: any) { - console.error(`[ERROR]:\n${error.stderr || error.message}`); - throw error; - } + console.log(`\n[CMD]: ${command}`); + try { + const { stdout, stderr } = await execPromise(command, { cwd: projectRoot }); + console.log(`[ERROR]:\n${stderr}`); + console.log(`[OUTPUT]:\n${stdout}`); + return stdout; + } catch (error: any) { + console.error(`[ERROR]:\n${error.stderr || error.message}`); + throw error; + } }; \ No newline at end of file From 4e56468415cf261e61fd559cc85505fe2ba8e7ba Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 15:08:44 +0300 Subject: [PATCH 14/18] timeout --- src/commands.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/commands.ts b/src/commands.ts index e67225b..37391b6 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -1413,12 +1413,14 @@ export class Commands { console.log('Approving token transfer...') const approveTx = await tokenContract.approve(escrowAddress, amountInUnits); await approveTx.wait(); + await new Promise(resolve => setTimeout(resolve, 3000)); console.log(`Successfully approved ${amount} ${token} to escrow`); console.log('Depositing to escrow...') const depositTx = await escrow.deposit(token, amount); await depositTx.wait(); + await new Promise(resolve => setTimeout(resolve, 3000)); return true; } catch (error) { From d3a0b4df822aadaefa62e759a8c3e7a8301b2352 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 15:52:41 +0300 Subject: [PATCH 15/18] revert to verifyfunds --- src/commands.ts | 64 +++++++++++++------------------------------------ 1 file changed, 16 insertions(+), 48 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 37391b6..52a0b84 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -732,56 +732,24 @@ export class Commands { console.log("Verifying payment..."); await new Promise(resolve => setTimeout(resolve, 3000)) - const payerAddress = await this.signer.getAddress(); - const payeeAddress = computeEnv.consumerAddress; - - const authorizations = await escrow.getAuthorizations( + const validationEscrow = await escrow.verifyFundsForEscrowPayment( paymentToken, - payerAddress, - payeeAddress - ); - - // If no authorization exists, create one - if (!authorizations || authorizations.length === 0) { - console.log(`Creating authorization for provider ${payeeAddress}...`); - const authorizeTx = await escrow.authorize( - getAddress(paymentToken), - getAddress(payeeAddress), - parsedProviderInitializeComputeJob.payment.amount.toString(), - parsedProviderInitializeComputeJob.payment.minLockSeconds.toString(), - '10' - ); - await authorizeTx.wait(); - console.log(`Successfully authorized provider ${payeeAddress}`); - } else { - console.log(`Provider ${payeeAddress} is already authorized`); - } - - // Check escrow balance and deposit if needed - const paymentAmount = await unitsToAmount(this.signer, paymentToken, parsedProviderInitializeComputeJob.payment.amount); - const escrowBalance = await escrow.getUserFunds(payerAddress, paymentToken); - const currentBalance = await unitsToAmount(this.signer, paymentToken, escrowBalance.available); - - console.log(`Current escrow balance: ${currentBalance}, Required: ${paymentAmount}`); - - if (Number(currentBalance) < Number(paymentAmount)) { - console.log(`Depositing ${paymentAmount} to escrow...`); - const depositSuccess = await this.depositToEscrow( - this.signer, - paymentToken, - paymentAmount, - Number((await this.signer.provider.getNetwork()).chainId) + computeEnv.consumerAddress, + await unitsToAmount(this.signer, paymentToken, parsedProviderInitializeComputeJob.payment.amount), + parsedProviderInitializeComputeJob.payment.amount.toString(), + parsedProviderInitializeComputeJob.payment.minLockSeconds.toString(), + '10' + ) + if (validationEscrow.isValid === false) { + console.error( + "Error starting compute job dataset DID " + + args[1] + + " and algorithm DID " + + args[2] + + " because escrow funds check failed: " + + validationEscrow.message ); - - if (!depositSuccess) { - console.error( - "Error starting compute job - escrow deposit failed for dataset DID " + - args[1] + - " and algorithm DID " + - args[2] - ); - return; - } + return; } console.log("Starting compute job using provider: ", providerURI); From 131238ce940de77b298bcc617b0e309eed1c5856 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 16:04:45 +0300 Subject: [PATCH 16/18] fix info h --- test/setup.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/setup.test.ts b/test/setup.test.ts index 1137624..8702483 100644 --- a/test/setup.test.ts +++ b/test/setup.test.ts @@ -8,6 +8,7 @@ import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) describe("Ocean CLI Setup", function() { + process.env.AVOID_LOOP_RUN = "true"; this.timeout(20000); // Set a longer timeout to allow the command to execute it("should return a valid response for 'npm run cli h'", function(done) { @@ -59,8 +60,6 @@ describe("Ocean CLI Setup", function() { expect(stdout).to.contain("Check if user(s) are on an access list"); expect(stdout).to.contain("removeFromAccessList"); expect(stdout).to.contain("Remove user(s) from an access list"); - expect(stdout).to.contain("getAccessListInfo"); - expect(stdout).to.contain("Get information about an access list"); done(); } catch (assertionError) { From 1e50cc694e83a00ef90b12673c55e0a1d5198dfe Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 16:32:22 +0300 Subject: [PATCH 17/18] cleanup --- src/commands.ts | 40 +++++++++++++++--------------------- test/paidComputeFlow.test.ts | 1 - test/util.ts | 8 +++----- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 52a0b84..112e8e2 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -781,27 +781,23 @@ export class Commands { metadataUri: await getMetadataURI(), }; - let computeJobs = null; - try { - computeJobs = await ProviderInstance.computeStart( - providerURI, - this.signer, - computeEnv.id, - assets, // assets[0] // only c2d v1, - algo, - supportedMaxJobDuration, - paymentToken, - JSON.parse(resources), - Number((await this.signer.provider.getNetwork()).chainId), - null, - null, - // additionalDatasets, only c2d v1 - output - ); - } catch (error) { - console.error("Error while starting the compute job: ", error); - throw new Error("Error while starting the compute job"); - } + const computeJobs = await ProviderInstance.computeStart( + providerURI, + this.signer, + computeEnv.id, + assets, // assets[0] // only c2d v1, + algo, + supportedMaxJobDuration, + paymentToken, + JSON.parse(resources), + Number((await this.signer.provider.getNetwork()).chainId), + null, + null, + // additionalDatasets, only c2d v1 + output + ); + + console.log("computeJobs: ", computeJobs); if (computeJobs && computeJobs[0]) { const { jobId, payment } = computeJobs[0]; @@ -1381,14 +1377,12 @@ export class Commands { console.log('Approving token transfer...') const approveTx = await tokenContract.approve(escrowAddress, amountInUnits); await approveTx.wait(); - await new Promise(resolve => setTimeout(resolve, 3000)); console.log(`Successfully approved ${amount} ${token} to escrow`); console.log('Depositing to escrow...') const depositTx = await escrow.deposit(token, amount); await depositTx.wait(); - await new Promise(resolve => setTimeout(resolve, 3000)); return true; } catch (error) { diff --git a/test/paidComputeFlow.test.ts b/test/paidComputeFlow.test.ts index f8326da..8847cb3 100644 --- a/test/paidComputeFlow.test.ts +++ b/test/paidComputeFlow.test.ts @@ -156,7 +156,6 @@ describe("Ocean CLI Paid Compute", function() { resources = [] const paymentToken = getAddresses().Ocean const output = await runCommand(`npm run cli -- startCompute ${computeDatasetDid} ${jsAlgoDid} ${computeEnvId} 900 ${paymentToken} '${JSON.stringify(resources)}' --accept true`); - console.log({ output: JSON.stringify(output, null, 2) }) const jobIdMatch = output.match(/JobID:\s*([^\s]+)/); const agreementIdMatch = output.match(/Agreement ID:\s*([^\s]+)/); diff --git a/test/util.ts b/test/util.ts index d29ca56..b42dbbc 100644 --- a/test/util.ts +++ b/test/util.ts @@ -2,8 +2,8 @@ import { exec } from "child_process"; import path from "path"; import util from "util"; -import { dirname } from 'path' -import { fileURLToPath } from 'url' +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; export const execPromise = util.promisify(exec); @@ -14,10 +14,8 @@ export const __dirname = dirname(__filename) export const projectRoot = path.resolve(__dirname, ".."); export const runCommand = async (command: string): Promise => { - console.log(`\n[CMD]: ${command}`); try { - const { stdout, stderr } = await execPromise(command, { cwd: projectRoot }); - console.log(`[ERROR]:\n${stderr}`); + const { stdout } = await execPromise(command, { cwd: projectRoot }); console.log(`[OUTPUT]:\n${stdout}`); return stdout; } catch (error: any) { From 4fc3360f93d23b03b7900e071978e02097c36edd Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Wed, 15 Oct 2025 16:36:37 +0300 Subject: [PATCH 18/18] log cmd --- test/util.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/util.ts b/test/util.ts index b42dbbc..a00cfcc 100644 --- a/test/util.ts +++ b/test/util.ts @@ -14,6 +14,7 @@ export const __dirname = dirname(__filename) export const projectRoot = path.resolve(__dirname, ".."); export const runCommand = async (command: string): Promise => { + console.log(`\n[CMD]: ${command}`); try { const { stdout } = await execPromise(command, { cwd: projectRoot }); console.log(`[OUTPUT]:\n${stdout}`);