feat: read-file + concat value resolvers and safe-exec-transaction std template#22
Open
Agusx1211 wants to merge 2 commits into
Open
feat: read-file + concat value resolvers and safe-exec-transaction std template#22Agusx1211 wants to merge 2 commits into
Agusx1211 wants to merge 2 commits into
Conversation
Adds two pure value resolvers to close gaps hit while building a
Safe execTransaction relay in live-contracts:
- read-file: reads a file's raw contents as a value (utf8/hex/json),
resolved relative to the job/template dir and confined to the project
root. The intended home for large, opaque, per-execution operational
blobs (e.g. packed multisig signatures) that don't belong in constants
and aren't typed build artifacts.
- concat: explicit string join for URL/path templating, avoiding the
ambiguity of interpolating {{...}} inside longer literals (only a whole
{{ref}} value is resolved today).
ExecutionContext gains an optional projectRoot (backwards-compatible) so
read-file can confine reads. Includes unit tests, README docs, and a
design note (notes/) covering the options considered and why a generic
blob registry is rejected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A std template that assembles and broadcasts a fully-signed Gnosis Safe execTransaction on-chain, rather than emitting calldata for a human to paste into the Safe UI. Built on abi-encode + send-transaction and the new read-file/concat resolvers. Takes a single resolved `signatures` argument; the caller chooses the source (read-file for offline/air-gapped, or json-request + read-json against a concat-built Safe Transaction Service URL for the hosted flow). Catapult has no conditional/coalesce resolver, so the file-vs-service choice deliberately lives with the caller rather than inside the template, keeping it single-responsibility (assemble + broadcast). No post-execution skip condition: the desired state is the inner call's effect, which the caller gates with job-level skip_if. Test parses the shipped YAML, runs it through the engine, and asserts the broadcast tx carries execTransaction calldata matching an independent ethers encoding. README documents both signature-source patterns. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two value resolvers and one std template, closing gaps hit while building a "Shape 1" Safe relay in
0xsequence/live-contracts— a catapult job that broadcasts a fully-signed Gnosis SafeexecTransactionon-chain, rather than emitting calldata for a human to paste into the Safe UI.1.
read-filevalue resolver — reads a file's raw contents as a value (utf8|hex|json), resolved relative to the job/template directory. The intended home for large, opaque, per-execution operational blobs (e.g. packed multisig signatures) that don't belong inconstantsand aren't typed build artifacts. Gitignorable.2.
concatvalue resolver — explicit string join for URL/path templating. Preferred over implicit whole-string interpolation: today a{{ref}}is only resolved when it is the entire value (value.match(/^{{(.*)}}$/)), so embedding a reference inside a longer URL was sent literally and 404'd us.3.
safe-exec-transactionstd template — assemblesexecTransaction(...)viaabi-encodeand broadcasts it viasend-transaction. Takes a single resolvedsignaturesargument; the caller chooses the source withread-file(offline/air-gapped) orjson-request+read-jsonagainst aconcat-built Safe Transaction Service URL (hosted flow). No post-execution skip condition — the desired state is the inner call's effect, which the caller gates with job-levelskip_if.Rejected: a generic "blob registry"
We considered a free-form "blob of data" store (a free-form
build-info) and rejected it: build-info earns its keep by being typed/validated and referenced semantically viaContract(name); a free-form analog is just "constants, but a second bag" with no added safety. The blob problem is better served by the smallest primitive that lets a blob live in its own file —read-file.Security (read-file)
path.relative(projectRoot, resolved); anything starting with..or absolute (escaping the root) is refused, so../../secretscan't climb out..env/keystores. The deployer key continues to arrive via env/CLI, never through this path.Design note
Full write-up of the options, the rejection rationale, the API, security, and the before/after live-contracts YAML:
notes/read-file-and-concat-value-resolvers.md.Test & build status
read-file(11) +concat(6) inresolver.spec.ts, andsafe-exec-transaction.spec.ts(2, parses the shipped YAML and asserts the broadcast tx carries execTransaction calldata matching an independent ethers encoding).pnpm build); lint 0 errors (only pre-existing repo-wideno-explicit-anywarnings).engine.spec.tsfailures (send-signed-transaction,test-nicks-method) are pre-existing and environmental — they fail identically on cleanmaster; those tests broadcast/mine and the local node is a Polygon fork, not a clean instant-mining anvil. Unrelated to this change.Final YAML shapes
🤖 Generated with Claude Code