From c4f3f2449651fd80db513362fe50934714acc1f9 Mon Sep 17 00:00:00 2001 From: Gorka Date: Fri, 15 May 2026 11:12:27 -0300 Subject: [PATCH 1/5] feat: setup-c adds US jurisdiction, setup-pp claims UY in join envelope --- setup-c.ts | 21 +++++++++++++++++++++ setup-pp.ts | 1 + 2 files changed, 22 insertions(+) diff --git a/setup-c.ts b/setup-c.ts index fcea259..d1951ac 100644 --- a/setup-c.ts +++ b/setup-c.ts @@ -297,6 +297,27 @@ async function main() { } console.log(` Channel added: ${channelContractId} (XLM)`); + const addJurisdictionRes = await fetch( + `${COUNCIL_URL}/api/v1/council/jurisdictions?councilId=${ + encodeURIComponent(channelAuthId) + }`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${adminJwt}`, + }, + body: JSON.stringify({ countryCode: "US" }), + }, + ); + if (!addJurisdictionRes.ok) { + throw new Error( + `Add jurisdiction failed: ${addJurisdictionRes.status} ${await addJurisdictionRes + .text()}`, + ); + } + console.log(" Jurisdiction added: US"); + console.log("\n[8/8] Write state file"); await writeStateFile({ ADMIN_PK: admin.publicKey(), diff --git a/setup-pp.ts b/setup-pp.ts index 906fcce..e17659c 100644 --- a/setup-pp.ts +++ b/setup-pp.ts @@ -306,6 +306,7 @@ async function main() { councilId: state.COUNCIL_ID, label: PP_LABEL, contactEmail: "pp@local-dev.moonlight.test", + jurisdictions: ["UY"], callbackEndpoint: PROVIDER_URL, }; const signedEnvelope = await signJoinEnvelope(joinPayload, ppKeypair); From ffb4924bf4b7164935be1abe1f5d64a6756cf7c9 Mon Sep 17 00:00:00 2001 From: Gorka Date: Fri, 15 May 2026 13:20:02 -0300 Subject: [PATCH 2/5] refactor: extract privacy-channel client helpers from e2e/ to lib/client/ --- deno.json | 9 + deno.lock | 416 ++++++++++++++++++++++++++++++++ docker-compose.e2e.yml | 2 + docker-compose.lifecycle.yml | 1 + docker-compose.otel.yml | 2 + e2e/dashboard.ts | 4 +- e2e/main.ts | 14 +- e2e/setup.sh | 2 +- e2e/verify-otel.ts | 4 +- {e2e => lib/client}/account.ts | 0 {e2e => lib/client}/auth.ts | 0 {e2e => lib/client}/bundle.ts | 0 {e2e => lib/client}/config.ts | 0 lib/client/deno.json | 9 + {e2e => lib/client}/deposit.ts | 0 {e2e => lib/client}/receive.ts | 0 {e2e => lib/client}/send.ts | 0 {e2e => lib/client}/tracer.ts | 4 +- {e2e => lib/client}/withdraw.ts | 0 lib/exercise-cp-spans.ts | 2 +- lifecycle/ci-test.ts | 12 +- lifecycle/main.ts | 12 +- lifecycle/testnet-verify.ts | 14 +- testnet/main.ts | 14 +- 24 files changed, 480 insertions(+), 41 deletions(-) create mode 100644 deno.json create mode 100644 deno.lock rename {e2e => lib/client}/account.ts (100%) rename {e2e => lib/client}/auth.ts (100%) rename {e2e => lib/client}/bundle.ts (100%) rename {e2e => lib/client}/config.ts (100%) create mode 100644 lib/client/deno.json rename {e2e => lib/client}/deposit.ts (100%) rename {e2e => lib/client}/receive.ts (100%) rename {e2e => lib/client}/send.ts (100%) rename {e2e => lib/client}/tracer.ts (96%) rename {e2e => lib/client}/withdraw.ts (100%) diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..3a42025 --- /dev/null +++ b/deno.json @@ -0,0 +1,9 @@ +{ + "nodeModulesDir": "auto", + "imports": { + "@colibri/core": "jsr:@colibri/core@^0.20.2", + "@moonlight/moonlight-sdk": "jsr:@moonlight/moonlight-sdk@^0.8.0", + "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0", + "stellar-sdk": "npm:@stellar/stellar-sdk@^15.0.1" + } +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..6f41f7d --- /dev/null +++ b/deno.lock @@ -0,0 +1,416 @@ +{ + "version": "5", + "specifiers": { + "jsr:@colibri/core@~0.20.2": "0.20.2", + "jsr:@fifo/convee@1.0.0": "1.0.0", + "jsr:@moonlight/moonlight-sdk@0.8": "0.8.0", + "jsr:@noble/curves@^1.8.0": "1.9.0", + "jsr:@noble/hashes@1.8.0": "1.8.0", + "jsr:@noble/hashes@^1.6.1": "1.8.0", + "jsr:@std/collections@^1.1.3": "1.1.7", + "jsr:@std/toml@^1.0.11": "1.0.11", + "npm:@opentelemetry/api@^1.9.0": "1.9.1", + "npm:@stellar/stellar-sdk@^15.0.1": "15.0.1", + "npm:asn1js@3.0.5": "3.0.5", + "npm:buffer@6.0.3": "6.0.3", + "npm:buffer@^6.0.3": "6.0.3" + }, + "jsr": { + "@colibri/core@0.20.2": { + "integrity": "2cf091a7d0045b542a9b45097a57d068c5388542243c24d7804fdbc08f5a74e1", + "dependencies": [ + "jsr:@fifo/convee", + "jsr:@std/toml", + "npm:@stellar/stellar-sdk", + "npm:buffer@^6.0.3" + ] + }, + "@fifo/convee@1.0.0": { + "integrity": "b61bfa222b9b8a53f0f2af1f35148fd54d86afc2fc3d6b5d073d56aaa369d9a3" + }, + "@moonlight/moonlight-sdk@0.8.0": { + "integrity": "680e75432c2d84707a9d7bf9df9564304066eb08d5dbc88eafdfe167eecfd423", + "dependencies": [ + "jsr:@colibri/core", + "jsr:@noble/curves", + "jsr:@noble/hashes@^1.6.1", + "npm:@stellar/stellar-sdk", + "npm:asn1js", + "npm:buffer@6.0.3" + ] + }, + "@noble/curves@1.9.0": { + "integrity": "efa55b3375b755706462a083060ee91e1f79973568cb670f02e885538ed1661b", + "dependencies": [ + "jsr:@noble/hashes@1.8.0" + ] + }, + "@noble/hashes@1.8.0": { + "integrity": "b52a2fcb4d02f8d8137871564a31f1ee9e2b0d15eedabbf32d2f7333f0abc939" + }, + "@std/collections@1.1.7": { + "integrity": "56f659d011218a69740b12829cf5ea2c9b70bbed0af02597e27dc1eb5e69e208" + }, + "@std/toml@1.0.11": { + "integrity": "e084988b872ca4bad6aedfb7350f6eeed0e8ba88e9ee5e1590621c5b5bb8f715", + "dependencies": [ + "jsr:@std/collections" + ] + } + }, + "npm": { + "@noble/curves@1.9.7": { + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "dependencies": [ + "@noble/hashes" + ] + }, + "@noble/hashes@1.8.0": { + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==" + }, + "@opentelemetry/api@1.9.1": { + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==" + }, + "@stellar/js-xdr@4.0.0": { + "integrity": "sha512-+NmNa7Tk5BI5XFdy/6xGTqAN4J9a9KgCrCGhj2uEUTCBhLkch0M+QbKzNH8zEnejWe0p8w+0q5hUVX6L3OzoVA==" + }, + "@stellar/stellar-base@15.0.0": { + "integrity": "sha512-XQhxUr9BYiEcFcgc4oWcCMR9QJCny/GmmGsuwPKf/ieIcOeb5149KLHYx9mJCA0ea8QbucR2/GzV58QbXOTxQA==", + "dependencies": [ + "@noble/curves", + "@stellar/js-xdr", + "base32.js", + "bignumber.js", + "buffer", + "sha.js" + ] + }, + "@stellar/stellar-sdk@15.0.1": { + "integrity": "sha512-iZjWKXtfohsPh+CX9wRyQNIlXLeA9VyuQB6UMC7AFBD9XnR92eOjnlfeONzk/Bsrkk6+UPlpzSy2MuF+ydHP1A==", + "dependencies": [ + "@stellar/stellar-base", + "axios", + "bignumber.js", + "commander", + "eventsource", + "feaxios", + "randombytes", + "toml", + "urijs" + ], + "bin": true + }, + "asn1js@3.0.5": { + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dependencies": [ + "pvtsutils", + "pvutils", + "tslib" + ] + }, + "asynckit@0.4.0": { + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "available-typed-arrays@1.0.7": { + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": [ + "possible-typed-array-names" + ] + }, + "axios@1.14.0": { + "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", + "dependencies": [ + "follow-redirects", + "form-data", + "proxy-from-env" + ] + }, + "base32.js@0.1.0": { + "integrity": "sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==" + }, + "base64-js@1.5.1": { + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bignumber.js@9.3.1": { + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==" + }, + "buffer@6.0.3": { + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dependencies": [ + "base64-js", + "ieee754" + ] + }, + "call-bind-apply-helpers@1.0.2": { + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": [ + "es-errors", + "function-bind" + ] + }, + "call-bind@1.0.9": { + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dependencies": [ + "call-bind-apply-helpers", + "es-define-property", + "get-intrinsic", + "set-function-length" + ] + }, + "call-bound@1.0.4": { + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dependencies": [ + "call-bind-apply-helpers", + "get-intrinsic" + ] + }, + "combined-stream@1.0.8": { + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": [ + "delayed-stream" + ] + }, + "commander@14.0.3": { + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==" + }, + "define-data-property@1.1.4": { + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": [ + "es-define-property", + "es-errors", + "gopd" + ] + }, + "delayed-stream@1.0.0": { + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "dunder-proto@1.0.1": { + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": [ + "call-bind-apply-helpers", + "es-errors", + "gopd" + ] + }, + "es-define-property@1.0.1": { + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + }, + "es-errors@1.3.0": { + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-object-atoms@1.1.1": { + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": [ + "es-errors" + ] + }, + "es-set-tostringtag@2.1.0": { + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": [ + "es-errors", + "get-intrinsic", + "has-tostringtag", + "hasown" + ] + }, + "eventsource@2.0.2": { + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==" + }, + "feaxios@0.0.23": { + "integrity": "sha512-eghR0A21fvbkcQBgZuMfQhrXxJzC0GNUGC9fXhBge33D+mFDTwl0aJ35zoQQn575BhyjQitRc5N4f+L4cP708g==", + "dependencies": [ + "is-retry-allowed" + ] + }, + "follow-redirects@1.16.0": { + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==" + }, + "for-each@0.3.5": { + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dependencies": [ + "is-callable" + ] + }, + "form-data@4.0.5": { + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dependencies": [ + "asynckit", + "combined-stream", + "es-set-tostringtag", + "hasown", + "mime-types" + ] + }, + "function-bind@1.1.2": { + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic@1.3.0": { + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": [ + "call-bind-apply-helpers", + "es-define-property", + "es-errors", + "es-object-atoms", + "function-bind", + "get-proto", + "gopd", + "has-symbols", + "hasown", + "math-intrinsics" + ] + }, + "get-proto@1.0.1": { + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": [ + "dunder-proto", + "es-object-atoms" + ] + }, + "gopd@1.2.0": { + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + }, + "has-property-descriptors@1.0.2": { + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": [ + "es-define-property" + ] + }, + "has-symbols@1.1.0": { + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag@1.0.2": { + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": [ + "has-symbols" + ] + }, + "hasown@2.0.3": { + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "dependencies": [ + "function-bind" + ] + }, + "ieee754@1.2.1": { + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inherits@2.0.4": { + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-callable@1.2.7": { + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-retry-allowed@3.0.0": { + "integrity": "sha512-9xH0xvoggby+u0uGF7cZXdrutWiBiaFG8ZT4YFPXL8NzkyAwX3AKGLeFQLvzDpM430+nDFBZ1LHkie/8ocL06A==" + }, + "is-typed-array@1.1.15": { + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dependencies": [ + "which-typed-array" + ] + }, + "isarray@2.0.5": { + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "math-intrinsics@1.1.0": { + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, + "mime-db@1.52.0": { + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types@2.1.35": { + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": [ + "mime-db" + ] + }, + "possible-typed-array-names@1.1.0": { + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==" + }, + "proxy-from-env@2.1.0": { + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==" + }, + "pvtsutils@1.3.6": { + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "dependencies": [ + "tslib" + ] + }, + "pvutils@1.1.5": { + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==" + }, + "randombytes@2.1.0": { + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": [ + "safe-buffer" + ] + }, + "safe-buffer@5.2.1": { + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "set-function-length@1.2.2": { + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": [ + "define-data-property", + "es-errors", + "function-bind", + "get-intrinsic", + "gopd", + "has-property-descriptors" + ] + }, + "sha.js@2.4.12": { + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dependencies": [ + "inherits", + "safe-buffer", + "to-buffer" + ], + "bin": true + }, + "to-buffer@1.2.2": { + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dependencies": [ + "isarray", + "safe-buffer", + "typed-array-buffer" + ] + }, + "toml@3.0.0": { + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, + "tslib@2.8.1": { + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "typed-array-buffer@1.0.3": { + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dependencies": [ + "call-bound", + "es-errors", + "is-typed-array" + ] + }, + "urijs@1.19.11": { + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" + }, + "which-typed-array@1.1.20": { + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dependencies": [ + "available-typed-arrays", + "call-bind", + "call-bound", + "for-each", + "get-proto", + "gopd", + "has-tostringtag" + ] + } + }, + "workspace": { + "dependencies": [ + "jsr:@colibri/core@~0.20.2", + "jsr:@moonlight/moonlight-sdk@0.8", + "npm:@opentelemetry/api@^1.9.0", + "npm:@stellar/stellar-sdk@^15.0.1" + ] + } +} diff --git a/docker-compose.e2e.yml b/docker-compose.e2e.yml index fed40bc..cae03ed 100644 --- a/docker-compose.e2e.yml +++ b/docker-compose.e2e.yml @@ -147,12 +147,14 @@ services: volumes: - shared-config:/config:ro - ./e2e:/e2e-src:ro + - ./lib:/lib-src:ro working_dir: /app entrypoint: - sh - -c - | cp /e2e-src/*.ts /e2e-src/deno.json . && cp /e2e-src/deno.lock . 2>/dev/null || true + mkdir -p ../lib && cp -r /lib-src/client ../lib/ deno install echo "Waiting for provider..." for i in $$(seq 1 60); do diff --git a/docker-compose.lifecycle.yml b/docker-compose.lifecycle.yml index a4b86b0..cb0a0f6 100644 --- a/docker-compose.lifecycle.yml +++ b/docker-compose.lifecycle.yml @@ -156,6 +156,7 @@ services: mkdir -p lifecycle lib e2e cp /lifecycle-src/*.ts lifecycle/ && cp /lifecycle-src/deno.json lifecycle/ && cp /lifecycle-src/deno.lock lifecycle/ 2>/dev/null || true cp /lib-src/*.ts lib/ + cp -r /lib-src/client lib/ cp /e2e-src/*.ts e2e/ cd lifecycle && deno install && cd .. echo "Waiting for provider and Stellar..." diff --git a/docker-compose.otel.yml b/docker-compose.otel.yml index 33b8e3a..9c500c0 100644 --- a/docker-compose.otel.yml +++ b/docker-compose.otel.yml @@ -147,12 +147,14 @@ services: volumes: - shared-config:/config:ro - ./e2e:/e2e-src:ro + - ./lib:/lib-src:ro working_dir: /app entrypoint: - sh - -c - | cp /e2e-src/*.ts /e2e-src/deno.json . && cp /e2e-src/deno.lock . 2>/dev/null || true + mkdir -p ../lib && cp -r /lib-src/client ../lib/ deno install echo "Waiting for provider..." for i in $$(seq 1 60); do diff --git a/e2e/dashboard.ts b/e2e/dashboard.ts index ec64bb3..3a7be04 100644 --- a/e2e/dashboard.ts +++ b/e2e/dashboard.ts @@ -1,7 +1,7 @@ import { Buffer } from "buffer"; import { Keypair } from "stellar-sdk"; -import type { Config } from "./config.ts"; -import { withE2ESpan } from "./tracer.ts"; +import type { Config } from "../lib/client/config.ts"; +import { withE2ESpan } from "../lib/client/tracer.ts"; /** * Dashboard E2E test — verifies the provider console API endpoints. diff --git a/e2e/main.ts b/e2e/main.ts index edf1861..293174e 100644 --- a/e2e/main.ts +++ b/e2e/main.ts @@ -1,11 +1,11 @@ import { Keypair } from "stellar-sdk"; -import { loadConfig } from "./config.ts"; -import { authenticate } from "./auth.ts"; -import { deposit } from "./deposit.ts"; -import { prepareReceive } from "./receive.ts"; -import { send } from "./send.ts"; -import { withdraw } from "./withdraw.ts"; -import { sdkTracer, withE2ESpan, writeTraceIds } from "./tracer.ts"; +import { loadConfig } from "../lib/client/config.ts"; +import { authenticate } from "../lib/client/auth.ts"; +import { deposit } from "../lib/client/deposit.ts"; +import { prepareReceive } from "../lib/client/receive.ts"; +import { send } from "../lib/client/send.ts"; +import { withdraw } from "../lib/client/withdraw.ts"; +import { sdkTracer, withE2ESpan, writeTraceIds } from "../lib/client/tracer.ts"; const DEPOSIT_AMOUNT = 10; // XLM const SEND_AMOUNT = 5; // XLM diff --git a/e2e/setup.sh b/e2e/setup.sh index 57130f1..61f96df 100755 --- a/e2e/setup.sh +++ b/e2e/setup.sh @@ -128,7 +128,7 @@ BUNDLE_MAX_OPERATIONS=20 EOF # --- Write shared config for test runner --- -# E2E_ prefix matches what e2e/config.ts expects +# E2E_ prefix matches what lib/client/config.ts expects cat > "$CONFIG_DIR/contracts.env" <(); const e2eStartTimeUs = Date.now() * 1000; // microseconds for Jaeger API -const TRACE_IDS_PATH = - new URL("./e2e-trace-ids.json", import.meta.url).pathname; +const TRACE_IDS_PATH = Deno.env.get("E2E_TRACE_IDS_PATH") ?? + "e2e-trace-ids.json"; function wrapOtelSpan( otelSpan: ReturnType, diff --git a/e2e/withdraw.ts b/lib/client/withdraw.ts similarity index 100% rename from e2e/withdraw.ts rename to lib/client/withdraw.ts diff --git a/lib/exercise-cp-spans.ts b/lib/exercise-cp-spans.ts index 29939c8..13096d4 100644 --- a/lib/exercise-cp-spans.ts +++ b/lib/exercise-cp-spans.ts @@ -16,7 +16,7 @@ * propagates a W3C traceparent header, giving us SDK-driver↔council-platform * trace continuity to assert against. */ -import { withE2ESpan } from "../e2e/tracer.ts"; +import { withE2ESpan } from "./client/tracer.ts"; export interface ExerciseCouncilSpansConfig { councilUrl: string; diff --git a/lifecycle/ci-test.ts b/lifecycle/ci-test.ts index 03e9845..8e5adfd 100644 --- a/lifecycle/ci-test.ts +++ b/lifecycle/ci-test.ts @@ -25,15 +25,15 @@ import { Keypair } from "stellar-sdk"; import { Buffer } from "node:buffer"; import { type ContractId, NetworkConfig } from "@colibri/core"; import type { StellarNetworkId } from "@moonlight/moonlight-sdk"; -import type { Config } from "../e2e/config.ts"; +import type { Config } from "../lib/client/config.ts"; import { createServer } from "../lib/soroban.ts"; import { addProvider } from "../lib/admin.ts"; import { extractEvents, verifyEvent } from "../lib/events.ts"; -import { authenticate } from "../e2e/auth.ts"; -import { deposit } from "../e2e/deposit.ts"; -import { prepareReceive } from "../e2e/receive.ts"; -import { send } from "../e2e/send.ts"; -import { withdraw } from "../e2e/withdraw.ts"; +import { authenticate } from "../lib/client/auth.ts"; +import { deposit } from "../lib/client/deposit.ts"; +import { prepareReceive } from "../lib/client/receive.ts"; +import { send } from "../lib/client/send.ts"; +import { withdraw } from "../lib/client/withdraw.ts"; const RPC_URL = Deno.env.get("STELLAR_RPC_URL")!; const FRIENDBOT_URL = Deno.env.get("FRIENDBOT_URL")!; diff --git a/lifecycle/main.ts b/lifecycle/main.ts index 7e8e8a8..6d324f2 100644 --- a/lifecycle/main.ts +++ b/lifecycle/main.ts @@ -12,13 +12,13 @@ import { import { addProvider, removeProvider } from "../lib/admin.ts"; import { extractEvents, verifyEvent } from "../lib/events.ts"; -import { authenticate } from "../e2e/auth.ts"; -import { deposit } from "../e2e/deposit.ts"; -import { prepareReceive } from "../e2e/receive.ts"; -import { send } from "../e2e/send.ts"; -import { withdraw } from "../e2e/withdraw.ts"; +import { authenticate } from "../lib/client/auth.ts"; +import { deposit } from "../lib/client/deposit.ts"; +import { prepareReceive } from "../lib/client/receive.ts"; +import { send } from "../lib/client/send.ts"; +import { withdraw } from "../lib/client/withdraw.ts"; -import type { Config } from "../e2e/config.ts"; +import type { Config } from "../lib/client/config.ts"; const DEPOSIT_AMOUNT = 10; // XLM const SEND_AMOUNT = 5; // XLM diff --git a/lifecycle/testnet-verify.ts b/lifecycle/testnet-verify.ts index 1ac432b..449b345 100644 --- a/lifecycle/testnet-verify.ts +++ b/lifecycle/testnet-verify.ts @@ -34,7 +34,7 @@ import { Keypair } from "stellar-sdk"; import { Buffer } from "node:buffer"; import { type ContractId, NetworkConfig } from "@colibri/core"; import type { StellarNetworkId } from "@moonlight/moonlight-sdk"; -import type { Config } from "../e2e/config.ts"; +import type { Config } from "../lib/client/config.ts"; import { deriveKeypair, masterSeedFromSecret, @@ -49,12 +49,12 @@ import { } from "../lib/deploy.ts"; import { addProvider } from "../lib/admin.ts"; import { extractEvents, verifyEvent } from "../lib/events.ts"; -import { authenticate } from "../e2e/auth.ts"; -import { deposit } from "../e2e/deposit.ts"; -import { prepareReceive } from "../e2e/receive.ts"; -import { send } from "../e2e/send.ts"; -import { withdraw } from "../e2e/withdraw.ts"; -import { sdkTracer, withE2ESpan, writeTraceIds } from "../e2e/tracer.ts"; +import { authenticate } from "../lib/client/auth.ts"; +import { deposit } from "../lib/client/deposit.ts"; +import { prepareReceive } from "../lib/client/receive.ts"; +import { send } from "../lib/client/send.ts"; +import { withdraw } from "../lib/client/withdraw.ts"; +import { sdkTracer, withE2ESpan, writeTraceIds } from "../lib/client/tracer.ts"; import { exerciseCouncilSpans } from "../lib/exercise-cp-spans.ts"; // ─── Testnet endpoints ──────────────────────────────────────────────── diff --git a/testnet/main.ts b/testnet/main.ts index 0d23d96..998176c 100644 --- a/testnet/main.ts +++ b/testnet/main.ts @@ -21,7 +21,7 @@ import { } from "../lib/master-seed.ts"; import { type ContractId, NetworkConfig } from "@colibri/core"; import type { StellarNetworkId } from "@moonlight/moonlight-sdk"; -import type { Config } from "../e2e/config.ts"; +import type { Config } from "../lib/client/config.ts"; import { createServer } from "../lib/soroban.ts"; import { deployChannelAuth, @@ -31,12 +31,12 @@ import { } from "../lib/deploy.ts"; import { addProvider } from "../lib/admin.ts"; import { extractEvents, verifyEvent } from "../lib/events.ts"; -import { authenticate } from "../e2e/auth.ts"; -import { deposit } from "../e2e/deposit.ts"; -import { prepareReceive } from "../e2e/receive.ts"; -import { send } from "../e2e/send.ts"; -import { withdraw } from "../e2e/withdraw.ts"; -import { sdkTracer, withE2ESpan, writeTraceIds } from "../e2e/tracer.ts"; +import { authenticate } from "../lib/client/auth.ts"; +import { deposit } from "../lib/client/deposit.ts"; +import { prepareReceive } from "../lib/client/receive.ts"; +import { send } from "../lib/client/send.ts"; +import { withdraw } from "../lib/client/withdraw.ts"; +import { sdkTracer, withE2ESpan, writeTraceIds } from "../lib/client/tracer.ts"; import { exerciseCouncilSpans } from "../lib/exercise-cp-spans.ts"; // ─── Testnet endpoints ────────────────────────────────────────────── From 9475cb234d4959335b80544312bb9c8739cf1964 Mon Sep 17 00:00:00 2001 From: Gorka Date: Fri, 15 May 2026 13:20:11 -0300 Subject: [PATCH 3/5] feat: add send-loop helper for firing bundles through the running PP --- send-loop.sh | 8 ++++ send-loop.ts | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100755 send-loop.sh create mode 100644 send-loop.ts diff --git a/send-loop.sh b/send-loop.sh new file mode 100755 index 0000000..23f3983 --- /dev/null +++ b/send-loop.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +DENO_BIN="${DENO_BIN:-deno}" +command -v "$DENO_BIN" >/dev/null 2>&1 || DENO_BIN="$HOME/.deno/bin/deno" + +cd "$(dirname "$0")" +exec "$DENO_BIN" run --allow-all send-loop.ts "$@" diff --git a/send-loop.ts b/send-loop.ts new file mode 100644 index 0000000..cbdfa7e --- /dev/null +++ b/send-loop.ts @@ -0,0 +1,121 @@ +/** + * Local Dev — Alice→Bob send loop + * + * Fires N (default 5) Alice→Bob privacy-channel sends through the running PP, + * sleeping `INTERVAL_MS` between each. Useful for watching the provider-console + * events tail update in real time. + * + * Reuses the lib/client helpers so the bundles travel the same code path as the + * e2e suite. + * + * Prereqs: ./up.sh → ./setup-c.sh → ./setup-pp.sh has run. + * + * Usage (preferred — via wrapper): + * ./send-loop.sh + * + * Usage (direct): + * deno run --allow-all send-loop.ts + * + * Env overrides: + * COUNT default 5 + * INTERVAL_MS default 1000 + * SEND_AMOUNT default 1 (XLM per send) + * STATE_FILE default ./.local-dev-state + */ +import { Keypair } from "stellar-sdk"; +import { authenticate } from "./lib/client/auth.ts"; +import { loadConfig } from "./lib/client/config.ts"; +import { deposit } from "./lib/client/deposit.ts"; +import { prepareReceive } from "./lib/client/receive.ts"; +import { send } from "./lib/client/send.ts"; + +const STATE_FILE = Deno.env.get("STATE_FILE") ?? + new URL("./.local-dev-state", import.meta.url).pathname; +const COUNT = Number(Deno.env.get("COUNT") ?? "5"); +const INTERVAL_MS = Number(Deno.env.get("INTERVAL_MS") ?? "1000"); +const SEND_AMOUNT = Number(Deno.env.get("SEND_AMOUNT") ?? "1"); + +const DEPOSIT_BUFFER = 2; // headroom for per-send fees + +function loadStateEnvVars(): void { + const content = Deno.readTextFileSync(STATE_FILE); + for (const line of content.split("\n")) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) continue; + const eq = trimmed.indexOf("="); + if (eq === -1) continue; + const key = trimmed.slice(0, eq); + const value = trimmed.slice(eq + 1); + if (key === "CHANNEL_ID") Deno.env.set("E2E_CHANNEL_CONTRACT_ID", value); + if (key === "COUNCIL_ID") Deno.env.set("E2E_CHANNEL_AUTH_ID", value); + if (key === "ASSET_ID") { + Deno.env.set("E2E_CHANNEL_ASSET_CONTRACT_ID", value); + } + if (key === "PROVIDER_URL") Deno.env.set("PROVIDER_URL", value); + if (key === "NETWORK_PASSPHRASE") { + Deno.env.set("STELLAR_NETWORK_PASSPHRASE", value); + } + if (key === "RPC_URL") Deno.env.set("STELLAR_RPC_URL", value); + if (key === "FRIENDBOT_URL") Deno.env.set("FRIENDBOT_URL", value); + } +} + +async function fund(friendbotUrl: string, publicKey: string): Promise { + const res = await fetch(`${friendbotUrl}?addr=${publicKey}`); + if (!res.ok && res.status !== 400) { + throw new Error( + `Friendbot failed for ${publicKey}: ${res.status} ${await res.text()}`, + ); + } +} + +async function main(): Promise { + loadStateEnvVars(); + const config = loadConfig(); + + console.log("\n=== local-dev — Alice→Bob send loop ===\n"); + console.log(` Count: ${COUNT}`); + console.log(` Interval: ${INTERVAL_MS}ms`); + console.log(` Send amount: ${SEND_AMOUNT} XLM`); + console.log(` Provider: ${config.providerUrl}`); + + const alice = Keypair.random(); + const bob = Keypair.random(); + console.log(` Alice: ${alice.publicKey()}`); + console.log(` Bob: ${bob.publicKey()}\n`); + + console.log("[1/4] Funding Alice + Bob via Friendbot"); + await fund(config.friendbotUrl, alice.publicKey()); + await fund(config.friendbotUrl, bob.publicKey()); + + console.log("[2/4] Authenticating both with provider"); + const aliceJwt = await authenticate(alice, config); + await authenticate(bob, config); + + const depositAmount = SEND_AMOUNT * COUNT + DEPOSIT_BUFFER; + console.log(`[3/4] Alice depositing ${depositAmount} XLM into channel`); + await deposit(alice.secret(), depositAmount, aliceJwt, config); + + console.log(`[4/4] Sending ${COUNT} bundles, ${INTERVAL_MS}ms apart\n`); + for (let i = 1; i <= COUNT; i++) { + const startedAt = Date.now(); + const receiverOps = await prepareReceive(bob.secret(), SEND_AMOUNT, config); + await send(alice.secret(), receiverOps, SEND_AMOUNT, aliceJwt, config); + console.log( + ` ${i}/${COUNT} sent ${SEND_AMOUNT} XLM (${ + Date.now() - startedAt + }ms)`, + ); + if (i < COUNT) { + await new Promise((r) => setTimeout(r, INTERVAL_MS)); + } + } + + console.log("\n=== Done ===\n"); +} + +main().catch((err) => { + console.error("\n=== send-loop FAILED ==="); + console.error(err); + Deno.exit(1); +}); From c0a9b375c580c56f107f7cb3d0a2dbd5faa30ade Mon Sep 17 00:00:00 2001 From: Gorka Date: Fri, 15 May 2026 14:00:13 -0300 Subject: [PATCH 4/5] chore: apply deno fmt --- lib/exercise-cp-spans.ts | 4 +++- send-loop.ts | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/exercise-cp-spans.ts b/lib/exercise-cp-spans.ts index 13096d4..c710dad 100644 --- a/lib/exercise-cp-spans.ts +++ b/lib/exercise-cp-spans.ts @@ -63,7 +63,9 @@ function logResult(res: Response, label: string, body: string): void { // 4xx/5xx — e.g. Escrow.releaseForRecipient legitimately 500s on a // freshly-created council with no on-chain UTXOs to release. Log // the failure and move on; the verifier asserts on span counts. - console.log(` ⚠️ ${label} returned ${res.status}: ${body.slice(0, 200)}`); + console.log( + ` ⚠️ ${label} returned ${res.status}: ${body.slice(0, 200)}`, + ); } } diff --git a/send-loop.ts b/send-loop.ts index cbdfa7e..9ef0e57 100644 --- a/send-loop.ts +++ b/send-loop.ts @@ -102,9 +102,7 @@ async function main(): Promise { const receiverOps = await prepareReceive(bob.secret(), SEND_AMOUNT, config); await send(alice.secret(), receiverOps, SEND_AMOUNT, aliceJwt, config); console.log( - ` ${i}/${COUNT} sent ${SEND_AMOUNT} XLM (${ - Date.now() - startedAt - }ms)`, + ` ${i}/${COUNT} sent ${SEND_AMOUNT} XLM (${Date.now() - startedAt}ms)`, ); if (i < COUNT) { await new Promise((r) => setTimeout(r, INTERVAL_MS)); From 58a5dbff2afae1a7efc334e6ddb7087ffea9d3a9 Mon Sep 17 00:00:00 2001 From: Gorka Date: Fri, 15 May 2026 14:18:26 -0300 Subject: [PATCH 5/5] fix(ci): mount + copy lib/client into e2e test-runner workspace --- e2e/docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 405a4f1..892714b 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -91,6 +91,7 @@ services: volumes: - shared-config:/config:ro - .:/src:ro + - ../lib:/lib-src:ro working_dir: /app environment: PROVIDER_URL: http://provider:3000 @@ -108,6 +109,7 @@ services: - -c - | cp /src/*.ts /src/deno.json . && cp /src/deno.lock . 2>/dev/null || true + mkdir -p ../lib && cp -r /lib-src/client ../lib/ deno install echo "Waiting for provider..." for i in $(seq 1 60); do