@ethernity-cloud/sdk-js 1.7.20 → 1.7.28

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/README.md CHANGED
@@ -98,7 +98,12 @@ The Pynithy securelock is built exactly as `ethernity-cloud-sdk-py` builds it
98
98
  your backend is frozen into. `src/serverless/requirements.txt` lists the
99
99
  Python packages your backend imports, and `src/serverless/Dockerfile.serverless`
100
100
  adds system packages to the securelock base image. `ECLD_MEMORY_TO_ALLOCATE`
101
- sets the enclave heap (default `1024M`).
101
+ sets the enclave heap (default `1024M`). A Nodenithy securelock built with a
102
+ heap under `1024M` (`ECLD_MEMORY_TO_ALLOCATE=256M`, for nodes with little
103
+ memory) runs node with `--jitless`, since V8's JIT reserves a 512 MB code
104
+ range that fits no smaller heap; the backend's JavaScript then runs
105
+ interpreted, about ten times slower in its crypto. The default `1024M` keeps
106
+ the JIT. `ECLD_NODE_JITLESS=0` or `1` overrides the choice.
102
107
 
103
108
  ### Scripts
104
109
 
package/cas/config.js CHANGED
@@ -21,6 +21,9 @@ const VALIDATOR_REGISTRY = {
21
21
  'ecld-nodenithy-litvm-testnet': '0xbE3759f327e8643fC5A1717fb2072A0dAcBAD29E',
22
22
  'ecld-pynithy-ethereum-sepolia': '0x8ad24b3F406A41a0F8D3440021792EB203957F43',
23
23
  'ecld-nodenithy-ethereum-sepolia': '0x8ad24b3F406A41a0F8D3440021792EB203957F43',
24
+ // Amoy's ValidatorRegistry of 2026-10-28 (ethernity-cas CAS-SETUP.md).
25
+ 'ecld-pynithy-amoy': '0x70bfdf41D4061592DF509b9b46F91a8457F88483',
26
+ 'ecld-nodenithy-amoy': '0x70bfdf41D4061592DF509b9b46F91a8457F88483',
24
27
  };
25
28
 
26
29
  const SESSION_REGISTRY = {
@@ -33,6 +36,9 @@ const SESSION_REGISTRY = {
33
36
  // Bound to Sepolia's ECImageRegistryV3 of 2026-10-14.
34
37
  'ecld-pynithy-ethereum-sepolia': '0xDbB249E108d19fC1691483Bf897bA8BA0dA99c06',
35
38
  'ecld-nodenithy-ethereum-sepolia': '0xDbB249E108d19fC1691483Bf897bA8BA0dA99c06',
39
+ // Bound to Amoy's ECImageRegistryV3 of 2026-10-28.
40
+ 'ecld-pynithy-amoy': '0x059662030fEeB4Ea8Fc7b05951A578d527a827e5',
41
+ 'ecld-nodenithy-amoy': '0x059662030fEeB4Ea8Fc7b05951A578d527a827e5',
36
42
  };
37
43
 
38
44
  // The chain the registries above live on. Sepolia's RPC is Tenderly's gateway:
@@ -44,6 +50,8 @@ const CHAIN = {
44
50
  'ecld-nodenithy-litvm-testnet': { rpcUrl: 'https://liteforge.rpc.caldera.xyz/infra-partner-http', chainId: 4441 },
45
51
  'ecld-pynithy-ethereum-sepolia': { rpcUrl: 'https://sepolia.gateway.tenderly.co', chainId: 11155111 },
46
52
  'ecld-nodenithy-ethereum-sepolia': { rpcUrl: 'https://sepolia.gateway.tenderly.co', chainId: 11155111 },
53
+ 'ecld-pynithy-amoy': { rpcUrl: 'https://polygon-amoy-bor-rpc.publicnode.com', chainId: 80002 },
54
+ 'ecld-nodenithy-amoy': { rpcUrl: 'https://polygon-amoy-bor-rpc.publicnode.com', chainId: 80002 },
47
55
  };
48
56
 
49
57
  // Whether the securelock takes its certificate from a CAS session: mainnet
@@ -67,6 +75,7 @@ const UNSAFE_NETWORKS = {
67
75
  Bloxberg_Testnet_Unsafe: 'Bloxberg_Testnet',
68
76
  LitVM_LiteForge_Unsafe: 'LitVM_LiteForge',
69
77
  Ethereum_Sepolia_Unsafe: 'Ethereum_Sepolia',
78
+ Polygon_Amoy_Testnet_Unsafe: 'Polygon_Amoy_Testnet',
70
79
  };
71
80
 
72
81
  // Case-insensitive: ecld-init writes Bloxberg_Testnet_Unsafe, a --network
@@ -98,12 +98,23 @@ async function latestRecord(reg, name) {
98
98
  return { id, hash: rec.sessionHash.toLowerCase(), creator: rec.creator };
99
99
  }
100
100
 
101
+ // The legacy gas price a registry write is sent with: the chain's eth_gasPrice
102
+ // plus 10 %, and 1 mwei at the least. The bloxberg testnet reports 1 mwei;
103
+ // Amoy's Bor reports about 30 gwei and refuses a price under its 25 gwei
104
+ // minimum tip; LitVM refuses a price under its base fee.
105
+ const MIN_GAS_PRICE = ethers.utils.parseUnits('1', 'mwei');
106
+ async function gasPrice(provider) {
107
+ const price = (await provider.getGasPrice()).mul(110).div(100);
108
+ return price.gt(MIN_GAS_PRICE) ? price : MIN_GAS_PRICE;
109
+ }
110
+
101
111
  // Send `method(...args)` to the registry. It is simulated first, so a call
102
112
  // the registry refuses stops with the registry's reason (`refused` names the
103
- // call), then sent with its gas estimate plus 30%: a registration's cost
104
- // grows with the length of the name. The wallet signs for the chain its RPC
105
- // serves (ethers takes no chainId override on a contract call), so an RPC
106
- // serving another chain than `chainId` is refused before anything is sent.
113
+ // call), then sent with its gas estimate plus 30% (a registration's cost
114
+ // grows with the length of the name) at the chain's gas price. The wallet
115
+ // signs for the chain its RPC serves (ethers takes no chainId override on a
116
+ // contract call), so an RPC serving another chain than `chainId` is refused
117
+ // before anything is sent.
107
118
  async function send(reg, chainId, refused, method, ...args) {
108
119
  const { chainId: served } = await reg.provider.getNetwork();
109
120
  if (served !== chainId) {
@@ -116,7 +127,7 @@ async function send(reg, chainId, refused, method, ...args) {
116
127
  }
117
128
  const gas = await reg.estimateGas[method](...args);
118
129
  const tx = await reg[method](...args, {
119
- gasLimit: gas.mul(13).div(10), gasPrice: ethers.utils.parseUnits('1', 'mwei'),
130
+ gasLimit: gas.mul(13).div(10), gasPrice: await gasPrice(reg.provider),
120
131
  });
121
132
  const rcpt = await tx.wait();
122
133
  if (rcpt.status !== 1) throw new Error(`SessionRegistry.${method} reverted for ${refused} (tx ${tx.hash})`);
package/info.js CHANGED
@@ -55,6 +55,15 @@ const NETWORKS = {
55
55
  imageRegistry: '0xAf8Ce29103E1f59feDD49688ff070Ffc2346AF1D',
56
56
  esr: '0x709052Fe77Af543d3d9FE2Ac06a15c635c8D4Be5',
57
57
  },
58
+ // The separate-ERC20 implementation 1.1 of 2026-10-28 on the storage and
59
+ // token of the previous implementation 0x1579b37C...; the V3 registry and
60
+ // the ESR of the same day.
61
+ POLYGON_AMOY_TESTNET: {
62
+ type: 'testnet', chainId: 80002, rpc: 'https://polygon-amoy-bor-rpc.publicnode.com',
63
+ protocol: '0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3',
64
+ imageRegistry: '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706',
65
+ esr: '0x1DC58496ed1cA66FD1E0b51fA28A9E7451970843',
66
+ },
58
67
  // The family of 2026-10-14, owned by 0xA247...; the previous PoX 0x29D3eC87...
59
68
  // and V1 registry 0x55e0ad45... are abandoned.
60
69
  ETHEREUM_SEPOLIA: {
package/init.js CHANGED
@@ -215,6 +215,7 @@ const main = async () => {
215
215
  "Bloxberg Testnet Unsafe",
216
216
  "LitVM LiteForge Unsafe",
217
217
  "Ethereum Sepolia Unsafe",
218
+ "Polygon Amoy Testnet Unsafe",
218
219
  ];
219
220
  const blockchainNetwork = await promptOptions(
220
221
  "On which Blockchain network do you want to have the app set up, as a starting point? (default is Bloxberg Testnet): ",
@@ -392,6 +393,7 @@ const main = async () => {
392
393
  "Bloxberg Testnet Unsafe": `etny-${svc}-testnet-unsafe`,
393
394
  "LitVM LiteForge Unsafe": `ecld-${svc}-litvm-testnet-unsafe`,
394
395
  "Ethereum Sepolia Unsafe": `ecld-${svc}-ethereum-sepolia-unsafe`,
396
+ "Polygon Amoy Testnet Unsafe": `ecld-${svc}-amoy-unsafe`,
395
397
  };
396
398
  const trustedZoneImage = imageByNetwork[blockchainNetwork] || `etny-${svc}-testnet`;
397
399
  writeEnv("TRUSTED_ZONE_IMAGE", trustedZoneImage);
package/network.js CHANGED
@@ -29,6 +29,8 @@ function networkFor({ ECAddress, ECNetworkByChainId }, raw) {
29
29
  POLYGON_MAINNET: { address: ECAddress.POLYGON.MAINNET_ADDRESS },
30
30
  POLYGON_AMOY: amoy,
31
31
  POLYGON_AMOY_TESTNET: amoy,
32
+ POLYGON_AMOY_UNSAFE: { ...amoy, unsafe: ['POLYGON', 'TESTNET_UNSAFE'] },
33
+ POLYGON_AMOY_TESTNET_UNSAFE: { ...amoy, unsafe: ['POLYGON', 'TESTNET_UNSAFE'] },
32
34
  IOTEX_TESTNET: { address: ECAddress.IOTEX.TESTNET_ADDRESS, chainId: ECNetworkByChainId.IOTEX.TESTNET, rpcUrl: 'https://babel-api.testnet.iotex.io' },
33
35
  ETHEREUM_SEPOLIA: sepolia,
34
36
  SEPOLIA: sepolia,
@@ -87,4 +87,6 @@ __SIGNED_MRENCLAVE__
87
87
 
88
88
  RUN rm -rf /enclave-key.pem
89
89
 
90
- ENTRYPOINT ["/usr/local/bin/node", "/etny-securelock/securelock.js"]
90
+ # The node flags (build.mjs NODE_FLAGS) are also the CAS session's command and
91
+ # the published .env's SECURELOCK_NODE_FLAGS; the composes run this ENTRYPOINT.
92
+ ENTRYPOINT ["/usr/local/bin/node"__NODE_FLAGS__, "/etny-securelock/securelock.js"]
@@ -21,6 +21,18 @@ const {executeTask} = require("./etny_exec");
21
21
  const {TaskStatus} = require("./task_status");
22
22
  const SwiftStreamService = require("./swift_stream_service");
23
23
 
24
+ // An error a network socket emits after its request's caller has moved on
25
+ // (a connection the server closed, ECONNRESET) reaches no handler of the
26
+ // request; without these the node runtime exits on it, and the task is lost.
27
+ // Logged and the run goes on: every step awaits its own result and treats a
28
+ // failed one.
29
+ process.on('uncaughtException', (e) => {
30
+ console.log('uncaught exception:', e && (e.stack || e.message) ? (e.stack || e.message) : e);
31
+ });
32
+ process.on('unhandledRejection', (e) => {
33
+ console.log('unhandled rejection:', e && (e.stack || e.message) ? (e.stack || e.message) : e);
34
+ });
35
+
24
36
  const contract_abi = require('./pox_abi');
25
37
  const image_registry_abi = require('./image_registry_abi');
26
38
  const {sha256} = require("./etny_crypto");
@@ -1,13 +1,19 @@
1
1
  const Minio = require('minio');
2
+ const http = require('http');
2
3
  const fs = require("fs");
3
4
  class SwiftStreamService {
4
5
  constructor(endpoint, port, accessKey, secretKey) {
6
+ // One connection per request: the minio client otherwise uses node's
7
+ // global agent, which keeps connections alive, and a connection the
8
+ // server has closed while this process computed between two requests
9
+ // fails the next request with ECONNRESET ("socket hang up").
5
10
  this.client = new Minio.Client({
6
11
  endPoint: endpoint,
7
12
  port: port,
8
13
  accessKey: accessKey,
9
14
  secretKey: secretKey,
10
15
  useSSL: false,
16
+ transportAgent: new http.Agent({ keepAlive: false }),
11
17
  });
12
18
  }
13
19
 
@@ -39,9 +39,11 @@ export const ECRunner = {
39
39
  // --- polygon mainnet ---
40
40
  'ecld-pynithy': ['0x439945BE73fD86fcC172179021991E96Beff3Cc4', '0x689f3806874d3c8A973f419a4eB24e6fBA7E830F', 'https://polygon-bor-rpc.publicnode.com', 137],
41
41
  'ecld-nodenithy': ['0x439945BE73fD86fcC172179021991E96Beff3Cc4', '0x689f3806874d3c8A973f419a4eB24e6fBA7E830F', 'https://polygon-bor-rpc.publicnode.com', 137],
42
- // --- polygon amoy testnet (replaces deprecated mumbai) ---
43
- 'ecld-pynithy-amoy': ['0x1579b37C5a69ae02dDd23263A2b1318DE66a27C3', '0xeFA33c3976f31961285Ae4f5D10188616C912728', 'https://rpc-amoy.polygon.technology', 80002],
44
- 'ecld-nodenithy-amoy': ['0x1579b37C5a69ae02dDd23263A2b1318DE66a27C3', '0xeFA33c3976f31961285Ae4f5D10188616C912728', 'https://rpc-amoy.polygon.technology', 80002],
42
+ // --- polygon amoy testnet: the separate-ERC20 PoX EthernityImplementationV2 1.1 and the ECImageRegistryV3 of 2026-10-28 ---
43
+ 'ecld-pynithy-amoy': ['0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3', '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706', 'https://polygon-amoy-bor-rpc.publicnode.com', 80002],
44
+ 'ecld-nodenithy-amoy': ['0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3', '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706', 'https://polygon-amoy-bor-rpc.publicnode.com', 80002],
45
+ 'ecld-pynithy-amoy-unsafe': ['0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3', '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706', 'https://polygon-amoy-bor-rpc.publicnode.com', 80002],
46
+ 'ecld-nodenithy-amoy-unsafe': ['0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3', '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706', 'https://polygon-amoy-bor-rpc.publicnode.com', 80002],
45
47
  // --- iotex testnet ---
46
48
  'ecld-pynithy-iotex-testnet': ['0xD56385A97413Ed80E28B1b54A193b98F2C49c975', '0xa7467A6391816be9367a1cC52E0ef0c15FfE3cCC', 'https://babel-api.testnet.iotex.io', 4690],
47
49
  'ecld-nodenithy-iotex-testnet': ['0xD56385A97413Ed80E28B1b54A193b98F2C49c975', '0xa7467A6391816be9367a1cC52E0ef0c15FfE3cCC', 'https://babel-api.testnet.iotex.io', 4690],
@@ -68,6 +70,7 @@ export const ECRunner = {
68
70
  // matching SessionRegistry.
69
71
  const require = createRequire(import.meta.url);
70
72
  const casConfig = require('../cas/config.js');
73
+ const nodeFlags = require('./nodeFlags.js');
71
74
  export const VALIDATOR_REGISTRY = casConfig.VALIDATOR_REGISTRY;
72
75
 
73
76
  // An -unsafe network runs an -unsafe trustedzone and nothing else, and an
@@ -215,6 +218,8 @@ const trustedZoneNetByBlockchain = {
215
218
  LitVM_LiteForge: 'litvm_liteforge',
216
219
  Bloxberg_Testnet_Unsafe: 'bloxberg_testnet_unsafe',
217
220
  LitVM_LiteForge_Unsafe: 'litvm_liteforge_unsafe',
221
+ Ethereum_Sepolia_Unsafe: 'ethereum_sepolia_unsafe',
222
+ Polygon_Amoy_Testnet_Unsafe: 'amoy_unsafe',
218
223
  };
219
224
  const trustedZoneNet = trustedZoneNetByBlockchain[process.env.BLOCKCHAIN_NETWORK];
220
225
  if (!trustedZoneNet) {
@@ -263,14 +268,17 @@ const esrEnvBlock = ESR_ENABLED ? `ENV ESR_CONTRACT_ADDRESS=${ESR_CONTRACT_ADDRE
263
268
  const dockerfileSecureTemplate = fs.readFileSync('Dockerfile.tmpl', 'utf8');
264
269
  let dockerfileSecureContent = dockerfileSecureTemplate.replace(/__ENCLAVE_NAME_SECURELOCK__/g, ENCLAVE_NAME_SECURELOCK).replace(/__NETWORK_TYPE__/g, isMainnet ? 'mainnet' : 'testnet').replace(/__BUCKET_NAME__/g, templateName + "-v3").replace(/__SMART_CONTRACT_ADDRESS__/g, ECRunner[templateName][0]).replace(/__IMAGE_REGISTRY_ADDRESS__/g, ECRunner[templateName][1]).replace(/__RPC_URL__/g, ECRunner[templateName][2]).replace(/__CHAIN_ID__/g, ECRunner[templateName][3]).replace(/__ETNY_VALIDATOR_REGISTRY_ADDRESS__/g, VALIDATOR_REGISTRY[templateName] || '').replace(/^__ESR_ENV__\r?\n/m, esrEnvBlock ? `${esrEnvBlock}\n` : '');
265
270
 
266
- // Amount of enclave heap to allocate (SCONE_HEAP). Kept in sync with the
267
- // run/docker-compose securelock service; overridable via ECLD_MEMORY_TO_ALLOCATE.
268
- // 1024M: with 256M or 512M the node runtime exhausts the protected heap
269
- // reserving its V8 code range at start, before the securelock runs.
271
+ // The securelock's protected heap (SCONE_HEAP), signed into the enclave and
272
+ // set on the run/docker-compose securelock service; ECLD_MEMORY_TO_ALLOCATE
273
+ // overrides the default. The default 1024M keeps V8's JIT, whose code range
274
+ // (512 MB, reserved at start) fits no smaller heap; a heap under 1024M runs
275
+ // node --jitless (nodeFlags.js), the backend's JavaScript interpreted.
270
276
  const MEMORY_TO_ALLOCATE = (process.env.ECLD_MEMORY_TO_ALLOCATE || '1024M').trim();
271
- // Read back by ecld-publish (run.js), which renders it into the composes'
272
- // securelock service.
277
+ const NODE_FLAGS = nodeFlags.securelockNodeFlags(MEMORY_TO_ALLOCATE);
278
+ // Read back by ecld-publish (run.js), which renders them into the composes'
279
+ // securelock service and the CAS session's command.
273
280
  writeEnv('MEMORY_TO_ALLOCATE', MEMORY_TO_ALLOCATE);
281
+ writeEnv('SECURELOCK_NODE_FLAGS', NODE_FLAGS.join(' '));
274
282
 
275
283
  // CRITICAL (mainnet DCAP): sign /usr/local/bin/node -- the binary the enclave
276
284
  // actually EXECUTES (ENTRYPOINT + the run/publish compose command both run
@@ -303,6 +311,7 @@ const signedMrenclaveStep =
303
311
  const cas = casConfig.casProvisioned(templateName, isMainnet);
304
312
  dockerfileSecureContent = dockerfileSecureContent
305
313
  .replace(/__MEMORY_TO_ALLOCATE__/g, MEMORY_TO_ALLOCATE)
314
+ .replace(/__NODE_FLAGS__/g, NODE_FLAGS.map((flag) => `, "${flag}"`).join(''))
306
315
  .replace('__SCONE_SIGN__', `RUN scone-signer sign ${signFlags}${cas ? ' --production' : ''} /usr/local/bin/node`)
307
316
  .replace('__SIGNED_MRENCLAVE__', signedMrenclaveStep);
308
317
 
@@ -0,0 +1,24 @@
1
+ // The node flags the securelock is built and run with, derived from its
2
+ // protected heap (SCONE_HEAP). V8 reserves a 512 MB code range for its JIT at
3
+ // start, which fits a 1024M heap and not a smaller one; a smaller heap runs
4
+ // node --jitless, which reserves no code range and runs JavaScript
5
+ // interpreted. ECLD_NODE_JITLESS=1 or 0 overrides the derivation.
6
+ const MEBIBYTE = 1024 * 1024;
7
+ const JIT_HEAP_BYTES = 1024 * MEBIBYTE;
8
+
9
+ // Bytes of a SCONE_HEAP value: a whole number with an optional K, M or G.
10
+ const heapBytes = (heap) => {
11
+ const m = /^(\d+)([KMG])?$/i.exec(String(heap).trim());
12
+ if (!m) throw new Error(`heap ${JSON.stringify(heap)}: expected <n>, <n>K, <n>M or <n>G`);
13
+ const unit = { K: 1024, M: MEBIBYTE, G: 1024 * MEBIBYTE }[(m[2] || '').toUpperCase()] || 1;
14
+ return Number(m[1]) * unit;
15
+ };
16
+
17
+ const securelockNodeFlags = (heap, override = process.env.ECLD_NODE_JITLESS) => {
18
+ const jitless = override === undefined || String(override).trim() === ''
19
+ ? heapBytes(heap) < JIT_HEAP_BYTES
20
+ : /^(1|true|yes)$/i.test(String(override).trim());
21
+ return jitless ? ['--jitless'] : [];
22
+ };
23
+
24
+ module.exports = { securelockNodeFlags, heapBytes, JIT_HEAP_BYTES };
@@ -30,8 +30,8 @@ services:
30
30
  container_name: etny-securelock
31
31
  privileged: true
32
32
  image: localhost:5000/etny-securelock
33
- entrypoint: ""
34
- command: [ "/usr/local/bin/node", "/etny-securelock/securelock.js" ]
33
+ # No command: the image's ENTRYPOINT runs node with the flags the
34
+ # securelock was built and measured with (build.mjs NODE_FLAGS).
35
35
  environment:
36
36
  - SCONE_CAS_ADDR=scone-cas.cf # __CAS_ONLY__
37
37
  - SCONE_LAS_ADDR=las # __CAS_ONLY__
@@ -33,8 +33,8 @@ services:
33
33
  container_name: etny-securelock
34
34
  privileged: true
35
35
  image: localhost:5000/etny-securelock
36
- entrypoint: ""
37
- command: [ "/usr/local/bin/node", "/etny-securelock/securelock.js" ]
36
+ # No command: the image's ENTRYPOINT runs node with the flags the
37
+ # securelock was built and measured with (build.mjs NODE_FLAGS).
38
38
  environment:
39
39
  - SCONE_CAS_ADDR=scone-cas.cf # __CAS_ONLY__
40
40
  - SCONE_LAS_ADDR=las # __CAS_ONLY__
@@ -16,7 +16,9 @@ services:
16
16
  - name: application
17
17
  image_name: application_image
18
18
  mrenclaves: [ "__MRENCLAVE__" ]
19
- command: /usr/local/bin/node /etny-securelock/securelock.js
19
+ # The command the enclave runs, applied from the session at attestation:
20
+ # the image ENTRYPOINT's, with the build's node flags (run.js NODE_FLAGS).
21
+ command: /usr/local/bin/node __NODE_FLAGS__/etny-securelock/securelock.js
20
22
  pwd: /
21
23
  environment:
22
24
  GREETING: hello from ETNY SECURELOCK!!!!
@@ -25,17 +25,19 @@ function setVars(network = "") {
25
25
  : "0x15D73a742529C3fb11f3FA32EF7f0CC3870ACA31";
26
26
  } else if (BLOCKCHAIN_NETWORK.includes("Polygon")) {
27
27
  if (BLOCKCHAIN_NETWORK.includes("Mainnet")) {
28
- NETWORK_RPC = "https://polygon-rpc.com";
28
+ NETWORK_RPC = "https://polygon-bor-rpc.publicnode.com";
29
29
  IMAGE_REGISTRY_ADDRESS = "0x689f3806874d3c8A973f419a4eB24e6fBA7E830F";
30
30
  CHAIN_ID = 137;
31
31
  GAS = 20000000;
32
32
  GAS_PRICE = 40500500010;
33
33
  } else {
34
+ // Amoy's ECImageRegistryV3 of 2026-10-28; the chain's base fee is
35
+ // about 30 gwei.
34
36
  NETWORK_RPC = "https://polygon-amoy-bor-rpc.publicnode.com";
35
- IMAGE_REGISTRY_ADDRESS = "0xF7F4eEb3d9a64387F4AcEb6d521b948E6E2fB049";
37
+ IMAGE_REGISTRY_ADDRESS = "0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706";
36
38
  CHAIN_ID = 80002;
37
39
  GAS = 20000000;
38
- GAS_PRICE = 1300000010;
40
+ GAS_PRICE = 40000000010;
39
41
  }
40
42
  } else if (BLOCKCHAIN_NETWORK.includes("LitVM")) {
41
43
  NETWORK_RPC = "https://liteforge.rpc.caldera.xyz/infra-partner-http";
package/nodenithy/run.js CHANGED
@@ -325,10 +325,15 @@ const main = async () => {
325
325
  PREDECESSOR_HASH_SECURELOCK = 'EMPTY';
326
326
  }
327
327
 
328
+ // The node flags the build gave the securelock (.env SECURELOCK_NODE_FLAGS,
329
+ // build.mjs): the session's command runs node with the same flags as the
330
+ // image ENTRYPOINT. A .env without the key is a build without flags.
331
+ const nodeFlags = (process.env.SECURELOCK_NODE_FLAGS || '').trim();
328
332
  const replacementsSecurelock = {
329
333
  PREDECESSOR: PREDECESSOR_HASH_SECURELOCK === 'EMPTY' ? `# predecessor: ${PREDECESSOR_HASH_SECURELOCK}` : `predecessor: ${PREDECESSOR_HASH_SECURELOCK}`,
330
334
  MRENCLAVE: process.env.MRENCLAVE_SECURELOCK,
331
335
  ENCLAVE_NAME: ENCLAVE_NAME_SECURELOCK,
336
+ NODE_FLAGS: nodeFlags ? `${nodeFlags} ` : '',
332
337
  ESR_ENVIRONMENT: casConfig.esrSessionEnvironment(process.env)
333
338
  };
334
339
  if (cas) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethernity-cloud/sdk-js",
3
- "version": "1.7.20",
3
+ "version": "1.7.28",
4
4
  "description": "A package to run ethernity cloud build scripts",
5
5
  "scripts": {
6
6
  "test": "node --test \"test/**/*.test.js\"",
package/pynithy/build.mjs CHANGED
@@ -39,9 +39,11 @@ export const ECRunner = {
39
39
  // --- polygon mainnet ---
40
40
  'ecld-pynithy': ['0x439945BE73fD86fcC172179021991E96Beff3Cc4', '0x689f3806874d3c8A973f419a4eB24e6fBA7E830F', 'https://polygon-bor-rpc.publicnode.com', 137],
41
41
  'ecld-nodenithy': ['0x439945BE73fD86fcC172179021991E96Beff3Cc4', '0x689f3806874d3c8A973f419a4eB24e6fBA7E830F', 'https://polygon-bor-rpc.publicnode.com', 137],
42
- // --- polygon amoy testnet (replaces deprecated mumbai) ---
43
- 'ecld-pynithy-amoy': ['0x1579b37C5a69ae02dDd23263A2b1318DE66a27C3', '0xeFA33c3976f31961285Ae4f5D10188616C912728', 'https://rpc-amoy.polygon.technology', 80002],
44
- 'ecld-nodenithy-amoy': ['0x1579b37C5a69ae02dDd23263A2b1318DE66a27C3', '0xeFA33c3976f31961285Ae4f5D10188616C912728', 'https://rpc-amoy.polygon.technology', 80002],
42
+ // --- polygon amoy testnet: the separate-ERC20 PoX EthernityImplementationV2 1.1 and the ECImageRegistryV3 of 2026-10-28 ---
43
+ 'ecld-pynithy-amoy': ['0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3', '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706', 'https://polygon-amoy-bor-rpc.publicnode.com', 80002],
44
+ 'ecld-nodenithy-amoy': ['0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3', '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706', 'https://polygon-amoy-bor-rpc.publicnode.com', 80002],
45
+ 'ecld-pynithy-amoy-unsafe': ['0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3', '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706', 'https://polygon-amoy-bor-rpc.publicnode.com', 80002],
46
+ 'ecld-nodenithy-amoy-unsafe': ['0xB8f46D2B943fFbe2A061Ae8be087ef5055AD96A3', '0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706', 'https://polygon-amoy-bor-rpc.publicnode.com', 80002],
45
47
  // --- iotex testnet ---
46
48
  'ecld-pynithy-iotex-testnet': ['0xD56385A97413Ed80E28B1b54A193b98F2C49c975', '0xa7467A6391816be9367a1cC52E0ef0c15FfE3cCC', 'https://babel-api.testnet.iotex.io', 4690],
47
49
  'ecld-nodenithy-iotex-testnet': ['0xD56385A97413Ed80E28B1b54A193b98F2C49c975', '0xa7467A6391816be9367a1cC52E0ef0c15FfE3cCC', 'https://babel-api.testnet.iotex.io', 4690],
@@ -25,17 +25,19 @@ function setVars(network = "") {
25
25
  : "0x15D73a742529C3fb11f3FA32EF7f0CC3870ACA31";
26
26
  } else if (BLOCKCHAIN_NETWORK.includes("Polygon")) {
27
27
  if (BLOCKCHAIN_NETWORK.includes("Mainnet")) {
28
- NETWORK_RPC = "https://polygon-rpc.com";
28
+ NETWORK_RPC = "https://polygon-bor-rpc.publicnode.com";
29
29
  IMAGE_REGISTRY_ADDRESS = "0x689f3806874d3c8A973f419a4eB24e6fBA7E830F";
30
30
  CHAIN_ID = 137;
31
31
  GAS = 20000000;
32
32
  GAS_PRICE = 40500500010;
33
33
  } else {
34
+ // Amoy's ECImageRegistryV3 of 2026-10-28; the chain's base fee is
35
+ // about 30 gwei.
34
36
  NETWORK_RPC = "https://polygon-amoy-bor-rpc.publicnode.com";
35
- IMAGE_REGISTRY_ADDRESS = "0xF7F4eEb3d9a64387F4AcEb6d521b948E6E2fB049";
37
+ IMAGE_REGISTRY_ADDRESS = "0x0C0f52ebd72cd2d2cBe94F385c9e23cec528b706";
36
38
  CHAIN_ID = 80002;
37
39
  GAS = 20000000;
38
- GAS_PRICE = 1300000010;
40
+ GAS_PRICE = 40000000010;
39
41
  }
40
42
  } else if (BLOCKCHAIN_NETWORK.includes("LitVM")) {
41
43
  NETWORK_RPC = "https://liteforge.rpc.caldera.xyz/infra-partner-http";