From a04dea651accd18cc131578cd65bb088a61454e4 Mon Sep 17 00:00:00 2001 From: paypes <43441600+abbesBenayache@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:17:08 +0100 Subject: [PATCH 1/2] feat(deployment): add TDX app deployment pipeline for Arbitrum --- .github/workflows/dapp-deploy.yml | 74 +++++++++++++++++-- deployment-dapp/src/config/config.ts | 3 - deployment-dapp/src/publishSellOrderScript.ts | 12 ++- .../src/singleFunction/deployApp.ts | 28 ++++--- .../src/singleFunction/publishSellOrder.ts | 18 ++--- .../src/singleFunction/pushSecret.ts | 11 +-- deployment-dapp/src/utils/validator.ts | 10 +++ 7 files changed, 119 insertions(+), 37 deletions(-) diff --git a/.github/workflows/dapp-deploy.yml b/.github/workflows/dapp-deploy.yml index 95b17bb..ab112bf 100644 --- a/.github/workflows/dapp-deploy.yml +++ b/.github/workflows/dapp-deploy.yml @@ -42,15 +42,14 @@ jobs: echo "clean_tag=dev" | tee -a $GITHUB_OUTPUT fi docker-publish: - uses: iExecBlockchainComputing/github-actions-workflows/.github/workflows/docker-build.yml@docker-build-v2.3.1 + uses: iExecBlockchainComputing/github-actions-workflows/.github/workflows/docker-build.yml@docker-build-v3.1.1 needs: [extract-tag] with: image-name: 'iexechub/web3telegram-dapp' registry: 'docker.io' dockerfile: 'dapp/Dockerfile' context: 'dapp' - security-scan: true - security-report: 'sarif' + security-scan: false hadolint: true push: true image-tag: ${{ needs.extract-tag.outputs.clean_tag }} @@ -59,6 +58,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PAT }} sconify: + if: startsWith(github.event.inputs.environment, 'bellecour-') uses: iExecBlockchainComputing/github-actions-workflows/.github/workflows/sconify.yml@sconify-v2.0.0 needs: [docker-publish, extract-tag] with: @@ -85,7 +85,70 @@ jobs: scontain-password: ${{ secrets.SCONTAIN_REGISTRY_PAT }} scone-signing-key: ${{ secrets.SCONIFY_SIGNING_PRIVATE_KEY }} - deploy-dapp: + deploy-tdx-dapp: + if: startsWith(github.event.inputs.environment, 'arbitrum-') + needs: [extract-tag, docker-publish] + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.19.0' + cache: 'npm' + + - name: Install dependencies + run: | + npm ci + cd node_modules/whitelist-smart-contract + npm install --save-dev ts-node + cd ../../deployment-dapp + npm ci + + - name: Deploy TDX dapp contract + env: + WALLET_PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} + DOCKER_IMAGE_TAG: ${{ needs.extract-tag.outputs.clean_tag }} + CHECKSUM: ${{ needs.docker-publish.outputs.checksum }} + RPC_URL: ${{ secrets.RPC_URL }} + run: | + cd deployment-dapp + npm run deploy-dapp + + - name: Push dapp secret + env: + WALLET_PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} + TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} + RPC_URL: ${{ secrets.RPC_URL }} + run: | + cd deployment-dapp + npm run push-dapp-secret + + - name: Publish free sell order + env: + WALLET_PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} + PRICE: ${{ vars.SELL_ORDER_PRICE }} + VOLUME: ${{ vars.SELL_ORDER_VOLUME }} + RPC_URL: ${{ secrets.RPC_URL }} + TEE_FRAMEWORK: ${{ vars.TEE_FRAMEWORK }} + run: | + cd deployment-dapp + npm run publish-sell-order + + - name: Add resource to whitelist + env: + CONTRACT_ADDRESS: ${{ vars.WEB3TELEGRAM_WHITELIST_CONTRACT_ADDRESS }} + PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} + run: | + cd node_modules/whitelist-smart-contract + export ADDRESS_TO_ADD=$(cat ../../deployment-dapp/.app-address) + npm run addResourceToWhitelist -- --network ${{ vars.WHITELIST_NETWORK_NAME }} + + deploy-scone-dapp: + if: startsWith(github.event.inputs.environment, 'bellecour-') needs: [extract-tag, sconify] runs-on: ubuntu-latest environment: ${{ inputs.environment }} @@ -107,7 +170,7 @@ jobs: cd ../../deployment-dapp npm ci - - name: Deploy dapp contract + - name: Deploy SCONE dapp contract env: WALLET_PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} DOCKER_IMAGE_TAG: ${{ needs.sconify.outputs.prod-image-tag }} @@ -134,6 +197,7 @@ jobs: PRICE: ${{ vars.SELL_ORDER_PRICE }} VOLUME: ${{ vars.SELL_ORDER_VOLUME }} RPC_URL: ${{ secrets.RPC_URL }} + TEE_FRAMEWORK: ${{ vars.TEE_FRAMEWORK }} run: | cd deployment-dapp npm run publish-sell-order diff --git a/deployment-dapp/src/config/config.ts b/deployment-dapp/src/config/config.ts index 68ad574..45514d0 100644 --- a/deployment-dapp/src/config/config.ts +++ b/deployment-dapp/src/config/config.ts @@ -3,9 +3,6 @@ //deployment parameters export const APP_NAME = 'web3telegram'; export const APP_TYPE = 'DOCKER'; -export const FRAMEWORK = 'scone'; - -export const APP_TAG = ['tee', 'scone']; export const DOCKER_IMAGE_NAMESPACE = 'iexechub'; export const DOCKER_IMAGE_REPOSITORY = 'web3telegram-dapp'; diff --git a/deployment-dapp/src/publishSellOrderScript.ts b/deployment-dapp/src/publishSellOrderScript.ts index 593b36e..c65021d 100644 --- a/deployment-dapp/src/publishSellOrderScript.ts +++ b/deployment-dapp/src/publishSellOrderScript.ts @@ -3,10 +3,12 @@ import { getIExec, loadAppAddress } from './utils/utils.js'; import { positiveNumberSchema, positiveStrictIntegerSchema, + teeFrameworkSchema, } from './utils/validator.js'; const main = async () => { - const { RPC_URL, WALLET_PRIVATE_KEY, PRICE, VOLUME } = process.env; + const { RPC_URL, WALLET_PRIVATE_KEY, PRICE, VOLUME, TEE_FRAMEWORK } = + process.env; const iexec = getIExec(WALLET_PRIVATE_KEY, RPC_URL); @@ -15,6 +17,10 @@ const main = async () => { if (!appAddress) throw Error('Failed to get app address'); // If the app was not deployed, do not continue // validate params + const teeFramework = await teeFrameworkSchema() + .label('TEE_FRAMEWORK') + .validate(TEE_FRAMEWORK ?? 'tdx'); + const price = await positiveNumberSchema() .required() .label('PRICE') @@ -28,8 +34,8 @@ const main = async () => { console.log(`Volume is ${volume}`); try { - //publish sell order for Tee app (scone) - await publishSellOrder(iexec, appAddress, price, volume); + // Publish sell order for TEE app + await publishSellOrder(iexec, appAddress, price, volume, teeFramework); } catch (e) { throw Error(`Failed to publish app sell order: ${e}`); } diff --git a/deployment-dapp/src/singleFunction/deployApp.ts b/deployment-dapp/src/singleFunction/deployApp.ts index f551368..d1055ec 100644 --- a/deployment-dapp/src/singleFunction/deployApp.ts +++ b/deployment-dapp/src/singleFunction/deployApp.ts @@ -12,6 +12,7 @@ export const deployApp = async ({ dockerRepository = DOCKER_IMAGE_REPOSITORY, dockerTag, checksum, + // TODO: to be deleted after migration to TDX fingerprint, sconifyVersion, }: { @@ -20,27 +21,36 @@ export const deployApp = async ({ dockerRepository?: string; dockerTag: string; checksum?: string; + // TODO: to be deleted after migration to TDX fingerprint?: string; - sconifyVersion: string; + sconifyVersion?: string; }): Promise => { const name = APP_NAME; const type = APP_TYPE; - console.log(`Using SCONIFY version: ${sconifyVersion}`); + let mrenclave; + + // TODO: to be deleted after migration to TDX + if (sconifyVersion) { + console.log( + `Using SCONE framework with SCONIFY version: ${sconifyVersion}`, + ); + mrenclave = { + framework: 'SCONE', // workaround framework not auto capitalized + version: `v${sconifyVersion.split('.').slice(0, 2).join('.')}`, // extracts "vX.Y" from "X.Y.Z-vN" format (e.g., "5.9.1-v16" → "v5.9") + entrypoint: 'node --disable-wasm-trap-handler /app/app.js', + heapSize: 1073741824, // 1GB + fingerprint, + }; + } - const mrenclave = { - framework: 'SCONE' as any, // workaround framework not auto capitalized - version: `v${sconifyVersion.split('.').slice(0, 2).join('.')}`, // extracts "vX.Y" from "X.Y.Z-vN" format (e.g., "5.9.1-v16" → "v5.9") - entrypoint: 'node --disable-wasm-trap-handler /app/app.js', - heapSize: 1073741824, // 1G - fingerprint, - }; const app = { owner: await iexec.wallet.getAddress(), name, type, multiaddr: `${dockerNamespace}/${dockerRepository}:${dockerTag}`, checksum, + // TODO: to be deleted after migration to TDX mrenclave, }; console.log(`Deploying app:\n${JSON.stringify(app, undefined, 2)}`); diff --git a/deployment-dapp/src/singleFunction/publishSellOrder.ts b/deployment-dapp/src/singleFunction/publishSellOrder.ts index 2ee23c5..0434d6f 100644 --- a/deployment-dapp/src/singleFunction/publishSellOrder.ts +++ b/deployment-dapp/src/singleFunction/publishSellOrder.ts @@ -1,27 +1,27 @@ -import { IExec } from 'iexec'; -import { APP_TAG } from '../config/config.js'; +import { IExec, TeeFramework } from 'iexec'; export const publishSellOrder = async ( iexec: IExec, appAddress: string, - price?: number, - volume?: number + price: number, + volume: number, + teeFramework: TeeFramework = 'tdx', ): Promise => { - const sconeTeeTag = APP_TAG; + const teeTag = ['tee', teeFramework]; console.log( - `Publishing apporder for app ${appAddress} with price ${price} xRLC and volume ${volume}` + `Publishing apporder for app ${appAddress} with price ${price} xRLC and volume ${volume} on ${teeTag}`, ); const apporderTemplate = await iexec.order.createApporder({ app: appAddress, appprice: price.toFixed(9) + ' RLC', - volume: volume, - tag: sconeTeeTag, + volume, + tag: teeTag, }); const apporder = await iexec.order.signApporder(apporderTemplate); const orderHash = await iexec.order.publishApporder(apporder); console.log( - `Published apporder ${orderHash}\n${JSON.stringify(apporder, undefined, 2)}` + `Published apporder ${orderHash}\n${JSON.stringify(apporder, undefined, 2)}`, ); return orderHash; }; diff --git a/deployment-dapp/src/singleFunction/pushSecret.ts b/deployment-dapp/src/singleFunction/pushSecret.ts index a935e87..27dd5e6 100644 --- a/deployment-dapp/src/singleFunction/pushSecret.ts +++ b/deployment-dapp/src/singleFunction/pushSecret.ts @@ -3,15 +3,10 @@ import { IExec } from 'iexec'; export const pushSecret = async ( iexec: IExec, appAddress: string, - secret: string + secret: string, ): Promise => { - const teeFramework = 'scone'; - console.log( - `Pushing app secret for app ${appAddress} on SMS ${teeFramework}` - ); - const isPushed = await iexec.app.pushAppSecret(appAddress, secret, { - teeFramework, - }); + console.log(`Pushing app secret for app ${appAddress}`); + const isPushed = await iexec.app.pushAppSecret(appAddress, secret); console.log(`success: ${isPushed}`); return isPushed; }; diff --git a/deployment-dapp/src/utils/validator.ts b/deployment-dapp/src/utils/validator.ts index 6afe5c4..bf54639 100644 --- a/deployment-dapp/src/utils/validator.ts +++ b/deployment-dapp/src/utils/validator.ts @@ -1,5 +1,15 @@ import { number, string } from 'yup'; +const TEE_FRAMEWORKS = ['tdx', 'scone', 'gramine'] as const; + +export const teeFrameworkSchema = () => + string() + .oneOf( + [...TEE_FRAMEWORKS], + `TEE_FRAMEWORK must be one of: ${TEE_FRAMEWORKS.join(', ')}`, + ) + .default('tdx'); + export const positiveNumberSchema = () => number().min(0); export const positiveStrictIntegerSchema = () => number().integer().positive(); From 0c035e35f660a2fea07fb2788926c98df362a75b Mon Sep 17 00:00:00 2001 From: paypes <43441600+abbesBenayache@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:27:22 +0100 Subject: [PATCH 2/2] style: run format --- deployment-dapp/src/singleFunction/deployApp.ts | 2 +- deployment-dapp/src/singleFunction/publishSellOrder.ts | 6 +++--- deployment-dapp/src/singleFunction/pushSecret.ts | 2 +- deployment-dapp/src/utils/validator.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/deployment-dapp/src/singleFunction/deployApp.ts b/deployment-dapp/src/singleFunction/deployApp.ts index d1055ec..7e9e6ae 100644 --- a/deployment-dapp/src/singleFunction/deployApp.ts +++ b/deployment-dapp/src/singleFunction/deployApp.ts @@ -33,7 +33,7 @@ export const deployApp = async ({ // TODO: to be deleted after migration to TDX if (sconifyVersion) { console.log( - `Using SCONE framework with SCONIFY version: ${sconifyVersion}`, + `Using SCONE framework with SCONIFY version: ${sconifyVersion}` ); mrenclave = { framework: 'SCONE', // workaround framework not auto capitalized diff --git a/deployment-dapp/src/singleFunction/publishSellOrder.ts b/deployment-dapp/src/singleFunction/publishSellOrder.ts index 0434d6f..311def5 100644 --- a/deployment-dapp/src/singleFunction/publishSellOrder.ts +++ b/deployment-dapp/src/singleFunction/publishSellOrder.ts @@ -5,11 +5,11 @@ export const publishSellOrder = async ( appAddress: string, price: number, volume: number, - teeFramework: TeeFramework = 'tdx', + teeFramework: TeeFramework = 'tdx' ): Promise => { const teeTag = ['tee', teeFramework]; console.log( - `Publishing apporder for app ${appAddress} with price ${price} xRLC and volume ${volume} on ${teeTag}`, + `Publishing apporder for app ${appAddress} with price ${price} xRLC and volume ${volume} on ${teeTag}` ); const apporderTemplate = await iexec.order.createApporder({ @@ -21,7 +21,7 @@ export const publishSellOrder = async ( const apporder = await iexec.order.signApporder(apporderTemplate); const orderHash = await iexec.order.publishApporder(apporder); console.log( - `Published apporder ${orderHash}\n${JSON.stringify(apporder, undefined, 2)}`, + `Published apporder ${orderHash}\n${JSON.stringify(apporder, undefined, 2)}` ); return orderHash; }; diff --git a/deployment-dapp/src/singleFunction/pushSecret.ts b/deployment-dapp/src/singleFunction/pushSecret.ts index 27dd5e6..f01e619 100644 --- a/deployment-dapp/src/singleFunction/pushSecret.ts +++ b/deployment-dapp/src/singleFunction/pushSecret.ts @@ -3,7 +3,7 @@ import { IExec } from 'iexec'; export const pushSecret = async ( iexec: IExec, appAddress: string, - secret: string, + secret: string ): Promise => { console.log(`Pushing app secret for app ${appAddress}`); const isPushed = await iexec.app.pushAppSecret(appAddress, secret); diff --git a/deployment-dapp/src/utils/validator.ts b/deployment-dapp/src/utils/validator.ts index bf54639..4f15941 100644 --- a/deployment-dapp/src/utils/validator.ts +++ b/deployment-dapp/src/utils/validator.ts @@ -6,7 +6,7 @@ export const teeFrameworkSchema = () => string() .oneOf( [...TEE_FRAMEWORKS], - `TEE_FRAMEWORK must be one of: ${TEE_FRAMEWORKS.join(', ')}`, + `TEE_FRAMEWORK must be one of: ${TEE_FRAMEWORKS.join(', ')}` ) .default('tdx');