@ethernity-cloud/sdk-js 1.7.0 → 1.7.7

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/publish.js CHANGED
@@ -46,6 +46,10 @@ async function prompt(question) {
46
46
  const { PROJECT_NAME, BLOCKCHAIN_NETWORK, PRIVATE_KEY, DEVELOPER_FEE, SERVICE_TYPE } = process.env;
47
47
  const scriptPath = path.resolve(__dirname, 'nodenithy/run/image_registry.js');
48
48
  process.env.NODE_NO_WARNINGS = 1
49
+ // image_registry.js reads the wallet's key from PRIVATE_KEY in its
50
+ // environment, never from its command line.
51
+ const registry = (args, privateKey) => execSync(`node ${scriptPath} ${args}`,
52
+ { env: { ...process.env, PRIVATE_KEY: privateKey } }).toString().trim();
49
53
  let result = '';
50
54
  if (!PROJECT_NAME || !BLOCKCHAIN_NETWORK || !PRIVATE_KEY || !DEVELOPER_FEE) {
51
55
  const hasWallet = await prompt('Do you have an existing wallet? (yes/no) (default value: no) ') || 'no';
@@ -57,12 +61,12 @@ async function prompt(question) {
57
61
  }
58
62
 
59
63
  let privateKey = await prompt('Enter your private key: ');
60
- result = execSync(`node ${scriptPath} "" "" "" "${privateKey}" "validateAddress"`).toString().trim();
64
+ result = registry('"" "" "" "validateAddress"', privateKey);
61
65
 
62
66
  while (result !== 'OK') {
63
67
  console.log(result);
64
68
  privateKey = await prompt('Invalid private key. Please enter a valid private key: ');
65
- result = execSync(`node ${scriptPath} "" "" "" "${privateKey}" "validateAddress"`).toString().trim();
69
+ result = registry('"" "" "" "validateAddress"', privateKey);
66
70
  }
67
71
 
68
72
  console.log('Inputted Private key is valid.');
@@ -70,32 +74,40 @@ async function prompt(question) {
70
74
  console.log()
71
75
  console.log('Checking blockchain for required funds...');
72
76
 
73
- result = execSync(`node ${scriptPath} "" "" "" "" "checkBalance"`).toString().trim();
77
+ result = registry('"" "" "" "checkBalance"', privateKey);
74
78
 
75
79
  console.log(`Available funds: ${result}`);
76
80
  console.log()
77
81
  const imageName = casConfig.nameOnNetwork(PROJECT_NAME, BLOCKCHAIN_NETWORK);
78
82
  console.log(`Checking if project name ${imageName} is available on ${BLOCKCHAIN_NETWORK} network and ownership...`);
79
- result = execSync(`node ${scriptPath} ${BLOCKCHAIN_NETWORK} ${imageName} ${process.env.VERSION} ${process.env.PRIVATE_KEY}`,).toString().trim();
83
+ // Exits 1, with the owner, when another wallet owns the name.
84
+ try {
85
+ result = registry(`${BLOCKCHAIN_NETWORK} ${imageName} ${process.env.VERSION}`, privateKey);
86
+ } catch (e) {
87
+ console.log((e.stdout || '').toString().trim());
88
+ process.exit(1);
89
+ }
80
90
  console.log(result);
81
91
  console.log()
82
92
 
83
- const taskPercentage = await prompt('Please specify the % of a task which will be transferred to your wallet upon successful execution (default 10%): ') || '10';
93
+ // The publisher's fee, in percent of each task's base price: PoX adds it
94
+ // to what the dApp user pays and pays it to the image's reward address.
95
+ const taskPercentage = await prompt('Your fee as the publisher of this image, in % of each task\'s base price, 0 to 15 (default 0): ') || '0';
84
96
  writeEnv('DEVELOPER_FEE', taskPercentage);
85
97
  } else {
86
98
  console.log('Using PROJECT_NAME, BLOCKCHAIN_NETWORK, PRIVATE_KEY, DEVELOPER_FEE from .env');
87
99
  console.log('Checking blockchain for required funds...');
88
- result = result = execSync(`node ${scriptPath} "" "" "" "" "checkBalance"`).toString().trim();
100
+ result = registry('"" "" "" "checkBalance"', PRIVATE_KEY);
89
101
 
90
102
  console.log(`Available funds: ${result}`);
91
103
  console.log()
92
104
  let privateKey = PRIVATE_KEY;
93
- result = execSync(`node ${scriptPath} "" "" "" "${privateKey}" "validateAddress"`).toString().trim();
105
+ result = registry('"" "" "" "validateAddress"', privateKey);
94
106
 
95
107
  while (result !== 'OK') {
96
108
  console.log(result);
97
109
  privateKey = await prompt('Invalid private key. Please enter a valid private key: ');
98
- result = execSync(`node ${scriptPath} "" "" "" "${privateKey}" "validateAddress"`).toString().trim();
110
+ result = registry('"" "" "" "validateAddress"', privateKey);
99
111
  }
100
112
  writeEnv('PRIVATE_KEY', privateKey);
101
113
  }
@@ -149,6 +149,16 @@ class EtnySecureLock:
149
149
  logging.info("Generated key and cert in memory based on MR_ENCLAVE")
150
150
  return private_key_pem, cert_pem
151
151
 
152
+ # The node-supplied bucket .env may only contribute the per-task order id.
153
+ # Everything else the securelock trusts is a per-network build constant
154
+ # (chain id, PoX contract, Image Registry, Web3 provider, ValidatorRegistry,
155
+ # bucket) set in __set_initializers, or a variable the CAS injects into the
156
+ # enclave process environment (ECAS_*, SCONE_*). Any key outside this set,
157
+ # and any key already present in the environment, is ignored.
158
+ NODE_ENV_ALLOWLIST = frozenset({
159
+ 'ETNY_ORDER_ID',
160
+ })
161
+
152
162
  @staticmethod
153
163
  def read_env_str(env_str: str):
154
164
  with io.StringIO(env_str) as f:
@@ -156,7 +166,13 @@ class EtnySecureLock:
156
166
  if '=' not in line:
157
167
  continue
158
168
  key, value = line.split('=', 1)
159
- os.environ[key.strip()] = re.sub(r'\n', '', value.strip())
169
+ key = key.strip()
170
+ if key not in EtnySecureLock.NODE_ENV_ALLOWLIST:
171
+ logging.info(f"Ignoring non-allowlisted .env key from the node bucket: {key}")
172
+ continue
173
+ if key in os.environ:
174
+ continue
175
+ os.environ[key] = re.sub(r'\n', '', value.strip())
160
176
  def validate_client_payload(self):
161
177
  payload_data = self.__get_file_content_and_decrypt(self.payload)
162
178
  input_data = self.__get_file_content_and_decrypt(self.input)
@@ -588,14 +604,10 @@ class EtnySecureLock:
588
604
  with open(path, 'r') as f:
589
605
  return f.read()
590
606
  def __load_env(self):
591
- if os.getenv('ETNY_CHAIN_ID'):
592
- self.chain_id = int(os.getenv('ETNY_CHAIN_ID'))
593
- if os.getenv('ETNY_SMART_CONTRACT_ADDRESS'):
594
- self.smart_contract_address = os.getenv('ETNY_SMART_CONTRACT_ADDRESS').rstrip()
595
- if os.getenv('ETNY_WEB3_PROVIDER'):
596
- self.web3_provider = os.getenv('ETNY_WEB3_PROVIDER').rstrip()
597
- if os.getenv('IMAGE_REGISTRY_ADDRESS'):
598
- self.image_registry_address = os.getenv('IMAGE_REGISTRY_ADDRESS').rstrip()
607
+ # The chain id, PoX contract, Image Registry and Web3 provider are the
608
+ # build constants of __set_initializers and are never read from the
609
+ # environment: the node supplies the environment, and an override would
610
+ # let it choose the registry the trustedzone's certificate comes from.
599
611
  self.order_id = int(os.getenv('ETNY_ORDER_ID'))
600
612
 
601
613
  def save_result(self):
package/pynithy/build.mjs CHANGED
@@ -31,9 +31,9 @@ const writeEnv = (key, value) => {
31
31
  // Kept in sync with etny-{pynithy,nodenithy}/v3/networks.yaml (the authoritative
32
32
  // on-chain constants). Covers all supported networks for both dApp types.
33
33
  export const ECRunner = {
34
- // --- bloxberg (the testnet reads ECImageRegistryV2, mainnet the original) ---
35
- 'etny-pynithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x99A84C624C028bdf0a855A1E9E3f2fcf7275B3D8', 'https://bloxberg.ethernity.cloud', 8995],
36
- 'etny-nodenithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x99A84C624C028bdf0a855A1E9E3f2fcf7275B3D8', 'https://bloxberg.ethernity.cloud', 8995],
34
+ // --- bloxberg (the testnet reads ECImageRegistryV3, mainnet the original) ---
35
+ 'etny-pynithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0xa372a6e1Eb7Fcf343AF6b91E809b900C55001CD1', 'https://bloxberg.ethernity.cloud', 8995],
36
+ 'etny-nodenithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0xa372a6e1Eb7Fcf343AF6b91E809b900C55001CD1', 'https://bloxberg.ethernity.cloud', 8995],
37
37
  'etny-pynithy': ['0x549A6E06BB2084100148D50F51CF77a3436C3Ae7', '0x15D73a742529C3fb11f3FA32EF7f0CC3870ACA31', 'https://bloxberg.ethernity.cloud', 8995],
38
38
  'etny-nodenithy': ['0x549A6E06BB2084100148D50F51CF77a3436C3Ae7', '0x15D73a742529C3fb11f3FA32EF7f0CC3870ACA31', 'https://bloxberg.ethernity.cloud', 8995],
39
39
  // --- polygon mainnet ---
@@ -52,8 +52,8 @@ export const ECRunner = {
52
52
  'ecld-pynithy-litvm-testnet': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441],
53
53
  'ecld-nodenithy-litvm-testnet': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441],
54
54
  // --- the -unsafe networks: the contracts of the network each is named after ---
55
- 'etny-pynithy-testnet-unsafe': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x99A84C624C028bdf0a855A1E9E3f2fcf7275B3D8', 'https://bloxberg.ethernity.cloud', 8995],
56
- 'etny-nodenithy-testnet-unsafe': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x99A84C624C028bdf0a855A1E9E3f2fcf7275B3D8', 'https://bloxberg.ethernity.cloud', 8995],
55
+ 'etny-pynithy-testnet-unsafe': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0xa372a6e1Eb7Fcf343AF6b91E809b900C55001CD1', 'https://bloxberg.ethernity.cloud', 8995],
56
+ 'etny-nodenithy-testnet-unsafe': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0xa372a6e1Eb7Fcf343AF6b91E809b900C55001CD1', 'https://bloxberg.ethernity.cloud', 8995],
57
57
  'ecld-pynithy-litvm-testnet-unsafe': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441],
58
58
  'ecld-nodenithy-litvm-testnet-unsafe': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441]
59
59
  };
@@ -99,11 +99,12 @@ const runCommand = (command, canPass = false) => {
99
99
 
100
100
  // Removes the containers this build and publish create, matched by exact name:
101
101
  // `--filter name=` matches a substring, so name=las would also match the LAS of
102
- // a CAS validator set on the same host.
102
+ // a CAS validator set on the same host. `-v` removes their anonymous volumes
103
+ // too: registry:2 keeps its pushed images in one, about 1.3 GB per build.
103
104
  const removeContainer = (name) => {
104
105
  const ids = shell.exec(`docker ps -a -q --filter "name=^/${name}$"`, { silent: true }).stdout.trim();
105
106
  if (ids) {
106
- runCommand(`docker rm -f ${ids.split('\n').join(' ')}`);
107
+ runCommand(`docker rm -f -v ${ids.split('\n').join(' ')}`);
107
108
  }
108
109
  };
109
110
 
package/pynithy/ipfs.mjs CHANGED
@@ -223,12 +223,13 @@ const retryOnFailure = async (fn, label) => {
223
223
  return null;
224
224
  };
225
225
 
226
- // Upload a single file: POST it to /api/v0/add and return its hash.
227
- const uploadFileToIPFSOnce = async (filePath) => {
226
+ // Upload a single file: POST it to /api/v0/add and return its hash. With
227
+ // onlyHash the node computes the same hash and stores nothing.
228
+ const uploadFileToIPFSOnce = async (filePath, onlyHash = false) => {
228
229
  const files = [filePath];
229
230
  const dir = path.dirname(filePath);
230
231
  const { body, boundary, length } = buildMultipartBody(files, dir);
231
- const { statusCode, text } = await postAdd('', body, boundary, length, null);
232
+ const { statusCode, text } = await postAdd(onlyHash ? '?only-hash=true' : '', body, boundary, length, null);
232
233
  if (statusCode !== 200) {
233
234
  console.log(`Failed to upload to IPFS. Status code: ${statusCode}`);
234
235
  return null;
@@ -260,13 +261,15 @@ const uploadFileToIPFS = async (filePath) => {
260
261
  };
261
262
 
262
263
  // Upload a whole directory with wrap-with-directory=true and return the root
263
- // directory hash -- the exact behaviour of Python's upload_dir.
264
- const uploadDirOnce = async (dirPath) => {
264
+ // directory hash -- the exact behaviour of Python's upload_dir. With onlyHash
265
+ // the node computes the same root hash and stores nothing.
266
+ const uploadDirOnce = async (dirPath, onlyHash = false) => {
265
267
  const abs = path.resolve(dirPath);
266
268
  const files = gatherFiles(abs);
267
269
  const totalSize = files.reduce((acc, f) => acc + fs.statSync(f).size, 0);
268
270
  const totalMb = Math.floor(totalSize / (1024 * 1024));
269
271
  const { body, boundary, length } = buildMultipartBody(files, abs);
272
+ const step = onlyHash ? 'Hashing enclave for IPFS' : 'Uploading and pinning enclave to IPFS';
270
273
 
271
274
  let lastShownMb = -1;
272
275
  let frame = 0;
@@ -276,27 +279,28 @@ const uploadDirOnce = async (dirPath) => {
276
279
  frame = (frame + 1) % SPINNER_FRAMES.length;
277
280
  lastShownMb = mb;
278
281
  process.stdout.write(
279
- `\r\t${SPINNER_FRAMES[frame]} Uploading and pinning enclave to IPFS... ${mb}MB/${totalMb}MB`
282
+ `\r\t${SPINNER_FRAMES[frame]} ${step}... ${mb}MB/${totalMb}MB`
280
283
  );
281
284
  }
282
285
  };
283
286
 
284
287
  const query =
285
- '?quieter=true&stream-channels=true&wrap-with-directory=true&progress=false&timeout=5m';
288
+ '?quieter=true&stream-channels=true&wrap-with-directory=true&progress=false&timeout=5m' +
289
+ (onlyHash ? '&only-hash=true' : '');
286
290
  const { statusCode, text } = await postAdd(query, body, boundary, length, onProgress);
287
291
 
288
292
  if (statusCode !== 200) {
289
- process.stdout.write(`\r\t${FAIL}Uploading and pinning enclave to IPFS\n`);
293
+ process.stdout.write(`\r\t${FAIL}${step}\n`);
290
294
  console.log(`Failed to upload to IPFS. Status code: ${statusCode}`);
291
295
  return false;
292
296
  }
293
297
  const rootHash = parseRootHash(text);
294
298
  if (!rootHash) {
295
- process.stdout.write(`\r\t${FAIL}Uploading and pinning enclave to IPFS\n`);
299
+ process.stdout.write(`\r\t${FAIL}${step}\n`);
296
300
  console.log('Failed to upload to IPFS. Could not determine root hash.');
297
301
  return false;
298
302
  }
299
- process.stdout.write(`\r\t${CHECK}Uploading and pinning enclave to IPFS\n`);
303
+ process.stdout.write(`\r\t${CHECK}${step}\n`);
300
304
  return rootHash;
301
305
  };
302
306
 
@@ -322,6 +326,16 @@ const upload = async (p) => {
322
326
  return null;
323
327
  };
324
328
 
329
+ // The hash `upload(p)` gives, from the same add call with only-hash: the IPFS
330
+ // node neither stores nor announces anything.
331
+ const hashForIPFS = async (p) => {
332
+ const stat = fs.statSync(p);
333
+ if (stat.isFile()) return retryOnFailure(() => uploadFileToIPFSOnce(p, true), 'hash_file');
334
+ if (stat.isDirectory()) return retryOnFailure(() => uploadDirOnce(p, true), 'hash_dir');
335
+ console.log(`Path ${p} is neither a file nor a directory.`);
336
+ return null;
337
+ };
338
+
325
339
  // ---------------------------------------------------------------------------
326
340
  // Download helpers (kubo-rpc-client based; unchanged behaviour)
327
341
  // ---------------------------------------------------------------------------
@@ -397,6 +411,7 @@ const getContentFromIPFS = async (hash, maxRetries = process.env.REACT_APP_IPFS_
397
411
  export {
398
412
  initialize,
399
413
  upload,
414
+ hashForIPFS,
400
415
  uploadFileToIPFS,
401
416
  uploadFolderToIPFS,
402
417
  getFromIPFS,
@@ -405,7 +420,7 @@ export {
405
420
  };
406
421
 
407
422
  // ---------------------------------------------------------------------------
408
- // CLI (unchanged interface: --host --action upload/download --filePath/--folderPath)
423
+ // CLI: --host --action upload/hash/download --filePath/--folderPath
409
424
  // ---------------------------------------------------------------------------
410
425
 
411
426
  program
@@ -413,7 +428,7 @@ program
413
428
  .option('--hhash <hhash>', 'IPFS hash')
414
429
  .option('--filePath <path>', 'Path to the file')
415
430
  .option('--folderPath <path>', 'Path to the folder')
416
- .option('--action <action>', 'Action to perform (upload, download)')
431
+ .option('--action <action>', 'Action to perform (upload, hash, download)')
417
432
  .option('--token <token>', 'IPFS authorization token')
418
433
  .option('--output <path>', 'Output path for download');
419
434
 
@@ -445,6 +460,15 @@ if (isMain) {
445
460
  console.error('Please provide a filePath or folderPath for upload.');
446
461
  process.exit(1);
447
462
  }
463
+ } else if (options.action === 'hash') {
464
+ const target = options.filePath || options.folderPath;
465
+ if (!target) {
466
+ console.error('Please provide a filePath or folderPath to hash.');
467
+ process.exit(1);
468
+ }
469
+ const hhash = await hashForIPFS(target);
470
+ console.log(`${hhash}`);
471
+ process.exit(hhash ? 0 : 1);
448
472
  } else if (options.action === 'download') {
449
473
  if (options.filePath) {
450
474
  await getFromIPFS(options.hhash, options.filePath);
@@ -456,7 +480,7 @@ if (isMain) {
456
480
  console.error('Please provide a filePath or folderPath for download.');
457
481
  }
458
482
  } else {
459
- console.error('Please provide a valid action (upload, download).');
483
+ console.error('Please provide a valid action (upload, hash, download).');
460
484
  process.exit(1);
461
485
  }
462
486
  };
@@ -1 +1 @@
1
- [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"AllowedWalletAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"AllowedWalletRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"},{"indexed":false,"internalType":"string","name":"publicKey","type":"string"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"ImageAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"ImagePublished","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"ImageRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"ImageValidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"TrustedZoneImageAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"TrustedZoneImageRemoved","type":"event"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"addAllowedWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"certPublicKey","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"}],"name":"addImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"certPublicKey","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"}],"name":"addTrustedZoneImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"address","name":"newRewardAddress","type":"address"}],"name":"changeImageRewardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"address","name":"newRewardAddress","type":"address"}],"name":"changeTrustedZoneImageRewardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"publishImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"removeAllowedWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"validateImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedWallets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getImageCertPublicKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getImageSession","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"getLatestImageVersionPublicKey","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"getLatestTrustedZoneImageCertPublicKey","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getRewardAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getTrustedZoneImageCertPublicKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getTrustedZoneImageSession","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getTrustedZoneRewardAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"imageDetails","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"validated","type":"bool"},{"internalType":"bool","name":"published","type":"bool"},{"internalType":"string","name":"certPublicKey","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"images","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"imageVersions","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"imageVersionsHash","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"trustedZoneImageDetails","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"validated","type":"bool"},{"internalType":"bool","name":"published","type":"bool"},{"internalType":"string","name":"certPublicKey","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"trustedZoneImageVersions","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"trustedZoneVersionsHash","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
1
+ [{"inputs":[{"internalType":"string","name":"imageName","type":"string"}],"name":"imageNameOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"AllowedWalletAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"AllowedWalletRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"},{"indexed":false,"internalType":"string","name":"publicKey","type":"string"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"ImageAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"ImagePublished","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"ImageRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"ImageValidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"TrustedZoneImageAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"}],"name":"TrustedZoneImageRemoved","type":"event"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"addAllowedWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"certPublicKey","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"}],"name":"addImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"certPublicKey","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"}],"name":"addTrustedZoneImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"address","name":"newRewardAddress","type":"address"}],"name":"changeImageRewardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"address","name":"newRewardAddress","type":"address"}],"name":"changeTrustedZoneImageRewardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"publishImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"removeAllowedWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"validateImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedWallets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getImageCertPublicKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getImageSession","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"getLatestImageVersionPublicKey","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"getLatestTrustedZoneImageCertPublicKey","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getRewardAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getTrustedZoneImageCertPublicKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getTrustedZoneImageSession","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"getTrustedZoneRewardAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"imageDetails","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"validated","type":"bool"},{"internalType":"bool","name":"published","type":"bool"},{"internalType":"string","name":"certPublicKey","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"images","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"imageVersions","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"imageVersionsHash","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"trustedZoneImageDetails","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"validated","type":"bool"},{"internalType":"bool","name":"published","type":"bool"},{"internalType":"string","name":"certPublicKey","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"trustedZoneImageVersions","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"trustedZoneVersionsHash","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"},{"indexed":false,"internalType":"string","name":"imageName","type":"string"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"ImageCertSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"ipfsHash","type":"string"},{"indexed":false,"internalType":"string","name":"imageName","type":"string"},{"indexed":false,"internalType":"string","name":"version","type":"string"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"string","name":"ipfsPeer","type":"string"}],"name":"ImageRegistered","type":"event"},{"inputs":[],"name":"pendingImages","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"string","name":"imageName","type":"string"},{"internalType":"string","name":"dockerComposeHash","type":"string"},{"internalType":"string","name":"session","type":"string"},{"internalType":"uint8","name":"fee","type":"uint8"},{"internalType":"string","name":"ipfsPeer","type":"string"}],"name":"registerImage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"registrationPeer","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"string","name":"certPublicKey","type":"string"}],"name":"setImageCert","outputs":[],"stateMutability":"nonpayable","type":"function"}]