AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
Rideploy la tua LUKSO Universal Profile allo stesso indirizzo su un'altra rete EVM. Nessuna chiave privata richiesta.
Translation pending
Developer toolsHTML · JavaScriptGitHub @ChainIntegrateOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Browser tools to redeploy a LUKSO Universal Profile at the same address on other EVM chains, then verify, test and use it there. No private keys: every transaction is signed in your own wallet.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Cross_Chain — LUKSO Universal Profile cross-chain toolkit
Browser tools by ChainIntegrate for redeploying an existing LUKSO Universal Profile (UP) at the same address on other EVM chains, then checking and using it there.Read the full README ↗Browser tools by ChainIntegrate for redeploying an existing LUKSO Universal Profile (UP) at the same address on other EVM chains, then checking and using it there.
What it contains, in short:
up-wallet.html, experimental): the UP's wallet on every network where it exists; it connects to dApps through WalletConnect, explains and simulates every request, and signs through the controller's wallet (MetaMask, on the website). Also an Android app and a browser extension, each signing with a key of its own kept on the device.Non-custodial throughout: the pages never hold a key, and every transaction is signed in the user's own wallet (in the Android app and the browser extension, with a key that stays on the device and that only the user can unlock).
Four parts. This README describes the whole system; each repository's own README describes its part in detail.
| Part | What it is | Where |
|---|---|---|
| The website | The toolkit (deploy, verify, backup controller, identity, NFT reception), UP Wallet, the gas relay's pages; the relayer (tools/relayer) and the contracts (contracts/) | this repository, public |
| UP Wallet for Android | UP Wallet on the phone, signing with the phone key (Android Keystore, fingerprint or PIN) | up-wallet-android, public |
| UP Wallet for the browser | UP Wallet on the computer (Chrome, Edge, Brave), signing with the computer key (passkey or password), with WalletConnect kept alive in the extension | up-wallet-extension, public |
| The signing service | The approvals of the paid paymaster and the subscriptions (gas paid by the site, beta) | private: it holds a key and its rules; described here and in AUDIT.md |
How they fit together:
UPSTREAM.json): the same checks, decoders and request window on the site, the phone and the computer. Changes to the page are collected in WALLET-BACKLOG.md and made in batches, then an app and an extension release.tools/relayer, public, in this repository) sends the UPs' operations to the network and pays their gas up front, refunded by the paymaster; the signing service (private) sends nothing and holds no funds: it only approves, with its key, the operations that the sponsor paymaster may pay. Both accept the website's and the extension's origins.| Website | https://crosschain-lukso.chainintegrate.it/ |
| Start here: the step-by-step guide | up-crosschain-guide.html |
| UP Wallet | up-wallet.html |
| Backup controller, and authorizing a device (the app's phone key, the extension's computer key) | up-backup.html |
| Gas paid by the site: check a UP | up-gas-relay.html |
| Android app (APK of each version) | up-wallet-android releases |
| Browser extension (zip of each version) | up-wallet-extension releases |
| Source code | this repository; the app in ChainIntegrate/up-wallet-android, the extension in ChainIntegrate/up-wallet-extension |
A UP is created by LUKSO's LSP23LinkedContractsFactory, which lives at the same address (0x2300000A84D25dF63081feAa37ba6b62C4c89a30) on every EVM chain where it has been published. The profile's address is a CREATE2 result computed from the entire original creation calldata (deployERC1167Proxies, selector 0x6a66a753). If you send that exact calldata to the factory on another chain, you get the same UP (LSP0) and Key Manager (LSP6) addresses there. The controller that gets control of the profile is the one named in that calldata.
A UP is a proxy that delegates everything to an implementation contract (LSP0 for the profile, LSP6 for the Key Manager). The implementation addresses are part of the calldata, and they depend on the contract version used by the tool that created the profile, not on the creation date. Two profiles created on the same day can therefore point to different versions. If a profile's implementations do not exist on the target chain, the redeployed profile would be "mute", so the Deploy tool blocks it.
LUKSO published its implementations through Nick's deterministic deployment proxy (0x4e59b44847b379578588920cA78FbF26c0B4956C), which lives at the same address on almost every EVM chain. Replaying the original transaction there creates the implementation at the same address. up-publish-implementation.html does this: it reads the original transaction from LUKSO, checks that it produces exactly the expected address, and has any wallet sign it. The operation is permissionless, gives nobody control over any profile, and only costs gas.
The first missing contracts published with up-publish-implementation.html, all through Nick's factory with one transaction per contract, with bytecode identical to LUKSO mainnet.
This list is frozen and will not be extended. If you publish missing LUKSO contracts on another chain, report them to LUKSO (for example with an issue in lsp-smart-contracts), not here. See CONTRIBUTING.md.
| Chain | Contract | Address | Transaction |
|---|---|---|---|
| Fuse | LSP23LinkedContractsFactory | 0x2300000A84D25dF63081feAa37ba6b62C4c89a30 | 0xdb03a728…4707790d |
| Fuse | UniversalProfileInitPostDeploymentModule | 0x000000000066093407b6704B89793beFfD0D8F00 | 0xa3cf07be…6481c090 |
| Fuse | UniversalProfileInit v0.14.0 | 0x3024D38EA2434BA6635003Dc1BDC0daB5882ED4F | 0xd6ad10b4…568cb703 |
| Fuse | LSP6KeyManagerInit v0.14.0 | 0x2Fe3AeD98684E7351aD2D408A43cE09a738BF8a4 | 0x46d68012…9ca9c120 |
| Polygon | UniversalProfileInit v0.12.1 | 0x52c90985AF970D4E0DC26Cb5D052505278aF32A9 | 0x7bcf539c…48c2cf |
The deployed bytecode is identical to LUKSO mainnet. LUKSO has been informed, with a request to verify the source code on Polygonscan: lukso-network/lsp-smart-contracts#1151.
The tools never ask for a private key. The calldata is public on-chain data, and every transaction is signed in your own wallet.
| File | Purpose |
|---|---|
up-deploy-public.html | Deploy tool (public). Connects your UP, decodes the calldata and checks that it produces your address. It shows every controller and its permissions, then checks the target chain: wallet/RPC chain match, free addresses, implementation bytecode, gas and balance. Finally it deploys and verifies the resulting bytecode. At the end it links to the backup page, with the same network and UP. It also has an optional LYX donation panel. |
up-backup.html | Backup controller. Adds a backup controller (a second account with exactly the signer's permissions, AllowedCalls included) or removes a lost one, on any network where the UP exists, LUKSO included: one Key Manager transaction, simulated first and re-read after confirmation. The UP's address comes from the extension or LUKSO's Universal Profiles app, or is typed; the genesis key is recognized from the UP's creation transaction on the LUKSO explorer (a calldata counts only if it predicts this UP's address). Authorize a device (the UP Wallet app from 0.9.0, the browser extension): adds the app's phone key or the extension's computer key as a controller with no admin permissions but access to the UP's funds, SUPER_CALL, SUPER_TRANSFERVALUE, SIGN, the 4337 permission and SETDATA restricted to LSP3Profile by AllowedERC725YDataKeys (never controllers, permissions or extensions), with the same checks, plan, simulation and re-read; ?phone= fills it in from the app. A lost phone is revoked with "Remove". Controller names: a name for each controller ("Office PC · extension"), kept on the UP on each network, so that the page and UP Wallet show it on every device: an LSP2 mapping key, bytes10(keccak256("UPWalletControllerName")) + 0000 + the controller's address, whose value is the name in UTF-8 (at most 64 characters, one line). Given with "Authorize a device" in the same transaction, or later for any controller (one setData, a label only); cleared with "Remove". Public, as the controllers' addresses are. One key per device by choice: no key is ever exported or copied between devices. |
up-verify-only.html | Verify only. A read-only check of whether a correct deploy of a given calldata exists on a chain, and whether the implementations it points to are present there. |
up-test-operazione.html | Test. Writes a test key () through the Key Manager and reads it back, to prove the controller can operate the profile on the new chain. |
The pages are published at https://crosschain-lukso.chainintegrate.it/. Start with the guide: up-crosschain-guide.html.
UP Wallet on the phone (up-wallet-android, 0.9.7 today, APKs on its GitHub releases, not on the Play Store yet). Since 0.9.0 the app is the wallet: it signs with a key created and kept on the phone (Android Keystore, fingerprint or PIN for every signature), with no MetaMask. dApps connect through WalletConnect (a link pasted or shared, or a QR code scanned), and a notification says when a request arrives. Experimental: the maintainer's own wallet, small amounts, at your own risk. Details (the key, the permissions, versions, the Play Store plan): its README. Privacy policy: up-wallet-app-privacy.html.
UP Wallet on the computer (up-wallet-extension, 0.1.7 today, zips on its GitHub releases, loaded in developer mode in Chrome, Edge or Brave). It is to the computer what the app is to the phone: it signs with a key kept in the extension, opened with a passkey (Windows Hello, Google Password Manager) or a password, in a small signing window that shows what is signed; WalletConnect lives in the extension, so dApps stay connected with the wallet closed. Experimental: the maintainer's own wallet, small amounts, at your own risk. Details (install and update, the key, the signing window): its README.
For both: one key per device, by choice. Each key is authorized once per network from the Backup page ("Authorize a device", signed by an admin controller such as MetaMask), with no admin permissions but access to all the UP's funds; a lost device is revoked alone, and the others keep working. Before a revoke, the device's panel ("This phone", "This computer") sends the key's own balance to the UP.
tools/decrypt.js (offline only)Only for people who know exactly what they are doing. You normally don't need it: the controller key can be exported directly from the Universal Profile extension (Settings → Developer → Reveal private key, guide step 1). The script only helps in unusual setups, for example an extension installation whose controller is not the profile's original one, when the original key is only in an old backup.
It runs locally and offline (node tools/decrypt.js); instructions are in tools/README.md. It is not served by the website (see below).
The site is deployed by running git pull in the web root (https://crosschain-lukso.chainintegrate.it/), so the whole repository lands on the server. The HTML pages, the shared scripts (site-ui.js, call-decode.js, abi-decode.js, token-image.js, chains.js, theme.js, backup-check.js, deploy-check.js, asset-list.js, sign-check.js, usd-price.js, op-cost.js, lifi-topup.js, gas-relay-client.js, gas-relay-page.js), vendor/, the images and guide-assets/ are website content. The .git/ folder and tools/ must not be reachable from the web.
The web server on this host does not apply .htaccess, so the protection is done in the server's git clone. It works with any web server. Run this once, inside the site folder on the server:
# 1. Keep tools/ out of the web root: files outside the pattern are removed now and on every future pull.
git sparse-checkout set --no-cone '/*' '!/tools/'
# 2. Move the git metadata out of the web root, into a folder shared by all sites' git dirs.
# Create it once (the only step that needs sudo), owned by the deploy user:
sudo mkdir -p /var/www/repos && sudo chown ubuntu:ubuntu /var/www/repos && sudo chmod 750 /var/www/repos
# `.git` becomes a one-line file containing only a path.
mv .git /var/www/repos/crosschain-lukso.git && echo "gitdir: /var/www/repos/crosschain-lukso.git" > .git
/var/www/repos is not the root of any site, so it is not reachable from the web. Always run git pull as the deploy user (ubuntu), never with sudo: root-owned files would break the next pull.
After that, git pull works exactly as before. The root .htaccess stays in the repository as an extra safety net for hosts that do apply it (Apache).
Site configuration. Some pages read their settings from config.js, which is not in the repository. Create it once on the server, in the site folder, by copying config.example.js and filling in the values; git pull leaves it untouched. Its values are not secret (the browser receives them): protect the WalletConnect Project ID with the allowed-domains list in the Reown dashboard, and the Alchemy API key (used by the Identity and UP Wallet pages to list a UP's tokens and NFTs) with the app's domain allowlist in the Alchemy dashboard.
Security headers. The web server (nginx) adds these headers to every response, pages and images: no other site may show the pages in a frame (X-Frame-Options: DENY, frame-ancestors 'none'; UP Wallet signs transactions, so it must not be framed by a site that could trick clicks), files keep their declared type (X-Content-Type-Options: nosniff), no referrer is sent (Referrer-Policy: no-referrer), and a fixed Content-Security-Policy:
default-src 'self'; script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com/ajax/libs/ethers/6.13.4/; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; connect-src 'self' https: wss://relay.walletconnect.org wss://relay.walletconnect.com; frame-src https://verify.walletconnect.org https://verify.walletconnect.com; worker-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'
connect-src allows any HTTPS host because the pages talk to the RPCs and explorers of many networks, custom RPCs included; img-src too, because profiles and tokens point to images anywhere. Scripts are restricted by a second policy in each page: a <meta http-equiv="Content-Security-Policy"> whose script-src allows the site's files, ethers from the CDN and the page's own inline scripts by their SHA-256 hash, nothing else. The browser applies both policies, so an injected script or an inline event handler does not run. node tools/csp.js writes the hashes; run it after every change to an inline script (node tools/csp.js --check only checks, as the GitHub workflow does on every push).
In production the site is served by nginx, and these nginx snippets are what applies; the root .htaccess only carries the same rules for a host running Apache (nginx ignores it). The headers are in /etc/nginx/snippets/security-headers.conf (the same file is committed as tools/nginx/security-headers.conf, with tools/nginx/crosschain-deny.conf; .htaccess sets the same headers for Apache), included in the site's server block and again in every location that has its own add_header (nginx drops the server-level headers there). The same server block includes /etc/nginx/snippets/crosschain-deny.conf, which returns 404 for dot files and folders (except /.well-known/, used to renew the certificate), /tools/ and every .md file, whatever the git clone contains. Check: curl -sI https://crosschain-lukso.chainintegrate.it/up-wallet.html.
Check after every deploy. Each of these URLs must return 404 Not Found:
https://crosschain-lukso.chainintegrate.it/.git/HEADhttps://crosschain-lukso.chainintegrate.it/.git/confighttps://crosschain-lukso.chainintegrate.it/tools/decrypt.jshttps://crosschain-lukso.chainintegrate.it/decrypt.js (old location, removed by the pull)https://crosschain-lukso.chainintegrate.it/.gitignorehttps://crosschain-lukso.chainintegrate.it/AUDIT.md (and any other .md, such as vendor/README.md)A direction, not a schedule. UP Wallet is growing towards a complete wallet for a Universal Profile on every network where it exists: open source, explaining every request in plain words, cross-chain first. Since 2026-10-25 the phone key comes first (it was step 6): the app signs by itself, with a key that stays on the phone, and MetaMask leaves the app. The website keeps signing through an external wallet.
.xpi signed by Mozilla as an unlisted add-on (installed with one click, updates included); dApps without WalletConnect in step 5; the extension stores later, after checking their rules for crypto wallets.abi-decode.js, app 0.8.0), with contracts named as the explorer names them; more networks as their explorers allow it. Name smart-account recipients from what they declare (ERC-7579 accountId()), as a hint.ethers 6.13.4 from cdnjs, pinned with Subresource Integrity; the WalletConnect bundles are served from this site (vendor/), with Subresource Integrity too. A Content-Security-Policy in every page lets only these files and the page's own inline scripts (by their hash) run.envio.lukso-mainnet.universal.tech, a UP or a recipient searched by name).Status: no professional audit yet. All the reviews below are the maintainer's own or AI-assisted, with local tests. None is a professional security audit. The contracts the gas relay depends on have never had a professional audit: UPPaymaster, UPVerifyingPaymaster and LUKSO's Extension4337, which LUKSO describes as experimental. A professional audit of the paymasters and the 4337 flow is required before the paid relay service holds significant customer funds. Until then, keep balances small and use the service at your own risk.
Last review (2026-10-29). An external, AI-assisted review of the whole project, the new browser extension included: not a professional audit, but an in-depth one (every repository's full diff, the extension's key handling read line by line, every earlier fix checked again in the code). No Critical, High or Medium; every earlier finding fixed. Three Low, accepted with their reasons: the extension's password fallback (the passkey is the recommended way), the site relayer on by default (UP Wallet's design), the server header's 'unsafe-inline' (the pages' own hash-based policy is the one that blocks scripts). Summary and status in AUDIT.md §17; its brief in §16.
Review policy (from 2026-10-29). The whole project is reviewed every six months by two LLMs of different providers, each from the same written brief, in separate environments with no shared context; the maintainer reads both reports and decides what to fix, and the decisions are recorded in AUDIT.md. The first pair was done on 2026-10-29 (Claude, section 17; Codex, its summary to come with the fixes); the next is due around April 2027. A structural change is reviewed again before its release, whatever the date: how a key is kept or signs (for example the key signing inside the hardware, roadmap step 8), the contracts, the gas relay's money flow, or a wider reach of the extension (dApps in the browser's tabs, roadmap step 5). Ordinary changes rely on the tests and the live tests until the next six-monthly pair. Not a professional audit, which stays planned for the gas relay when the paid service has significant users or funds.
| Date | Scope | Result | Report |
|---|---|---|---|
| 2026-09-27 | Whole repository and git history (commit f56dd29) | 2 High, 8 Medium, 9 Low, 6 Informational. All High and Medium findings are fixed. | AUDIT.md |
| 2026-09-29 | WalletConnect pages: up-wallet.html, up-walletconnect-basenames.html, vendored WalletKit (commit 47642bc) | 1 Medium, 3 Low (all fixed), 7 Informational (accepted or planned). Tested live on Base and Polygon. | AUDIT.md §7 |
| 2026-10-01 | Gas relay: Extension4337, UPPaymaster, relayer, the three Base UPs (AI-assisted) | The 4337 setup adds no way to move funds beyond what the controller key already allows. Findings fixed or tracked. | AUDIT.md §8 |
| 2026-10-02 | Whole repository at 40f0bc0, system live (AI-assisted) | 2 High and 3 of 4 Medium fixed; M-1 (paymaster gas per operation) open, bounded by the caps; some Low and Info in the hardening backlog. | AUDIT.md §9 |
| 2026-10-04 | UPVerifyingPaymaster (AI-assisted) | No Critical, High or Medium bug in the code. The signing key's power (VP-H1) is mitigated off-chain; Low and Info fixed or accepted. | AUDIT.md §10 |
| 2026-10-04, 2026-10-05 | Launch reviews of the whole system, toolkit and private signing service (AI-assisted; the second covers paid subscriptions) | No Critical or High. One Medium on the availability of the paid service (SP-A, no funds at risk; fixed with SP-B) and Low items open. H-1 and H-2 confirmed fixed. |
Main fixes from the 2026-09-27 audit:
owner(), instead of using a hard-coded implementation.tools/decrypt.js (moved out of the published files) rewritten: interactive input (public salt/IV kept as defaults), hidden password prompt, input validation.Follow-up on the same date: gas prices are now read directly from the RPC. Before, ethers called a third-party gas-station API on Polygon, and the checks failed when that service was unreachable (AUDIT.md L-09).
Main fixes from the 2026-09-29 review of the WalletConnect pages:
The remaining recommendations (periodic RPC refresh, a second review of UP Wallet before removing its "experimental" label) are listed in AUDIT.md §5.
Bug reports and improvements to the tools are welcome. This repository does not add new chains: the tools already work on any EVM chain through "Custom RPC", and official support for a chain is LUKSO's responsibility. Read CONTRIBUTING.md before opening an issue or a pull request.
Released under the MIT License, with these exceptions:
contracts/UPPaymaster.sol and contracts/UPVerifyingPaymaster.sol are under GPL-3.0 (text), like the ERC-4337 interfaces (@account-abstraction/contracts, GPL-3.0) they are built on.vendor/ (WalletConnect Community License Agreement of Reown, Inc., plus MIT/ISC/Apache-2.0/0BSD dependencies), the QR code library (MIT) and the sources embedded in contracts/*.input.json (LUKSO, ERC725, OpenZeppelin, @account-abstraction). See THIRD_PARTY_NOTICES.md.The software is provided "as is", without warranty of any kind: these tools prepare irreversible on-chain transactions, and you use them at your own risk.
The ChainIntegrate name, logo and banner are not covered by the license.
The site relayer in tools/relayer/ is run by ChainIntegrate. It relays the operations of the UPs on the allowlist paymaster's list and of the UPs with an active subscription (sponsor paymaster, up-subscribe.html). Both are experimental and offered as they are.
| Polygon | LSP6KeyManagerInit v0.12.1 | 0xa75684d7D048704a2DB851D05Ba0c3cbe226264C | 0xb29fae94…83bce8 |
up.test.pingup-invia-fondi.html | Send (moved). The Send page was merged into UP Wallet (panel 6, below), which sends the currency, tokens and NFTs from the UP, lists what it holds, and checks the result after sending. The file only says so and links there, so old links keep working. |
up-publish-implementation.html | Publish implementation. Publishes on the target chain a LUKSO implementation (LSP0 or Key Manager) that is missing there, at the same address, by replaying LUKSO's original deploy through Nick's factory. The Verify and Deploy pages link to it when an implementation is missing. It also publishes ChainIntegrate's NFT reception extension (shortcut on the page), which is on LUKSO through Nick's factory as well; the NFT reception page links to it. Any wallet can do it. |
site-ui.js | Shared look of the tool pages, in line with UP Wallet: the language from the browser, remembered and shared with UP Wallet; a page's warnings in a window at its first opening, with its acceptance box when it has one (remembered per page; "Not now" leaves them unaccepted and the page's own rules still apply); the main networks as buttons with their logo, with a green dot where the UP exists when the page asks for its address; long explanations shortened to three lines with "Read more"; the UP's address from the extension or, without one (for example on a phone), from LUKSO's Universal Profiles app via WalletConnect (only the address is read, then the session is closed). Where the browser has no wallet (a phone), the signing wallet is MetaMask on the phone through WalletConnect: transactions and signatures go to the app, reads go to the network's RPC, and the session is kept until "Disconnect" (used by every tool page that signs: Deploy, Backup, NFT receiving, gas relay, subscription, Test and Publish). It only moves the page's elements and adds buttons: each page keeps its texts, checks and flow. |
chains.js | Shared built-in chain metadata, loaded by every active tool page (all except the deprecated v2 page). Pages that emit explorer links supply the relevant address or transaction path. |
gas-relay-client.js | Shared code for the "Pay the gas with the site relayer" option of the UP Wallet and the subscription page. It checks, read-only, whether the option applies: site relayer on the network; a paymaster that will pay, either the allowlist paymaster (UPPaymaster, UP on its list, cap and deposit) or the sponsor paymaster (UPVerifyingPaymaster, UP accepted by the signing service, with the subscription balance and the price shown); Extension4337, EntryPoint exactly 0x500, controller with the 4337 permission. With the sponsor paymaster it asks the signing service for an approval and checks it (paymaster, length, validity window, signature by the on-chain signer()) before the controller signs. It builds and simulates the ERC-4337 operation for UP.execute(CALL, to, value, data) on the EntryPoint path, checks its maximum cost against the cap and deposit, has the controller sign the operation hash (a message, no gas), posts it to the site relayer and reads the outcome from UserOperationEvent. Calls and value transfers only: data and controller changes never go through the relayer (AUDIT G-M2). An undecoded revert is shown by its first bytes, a decoded reason on one line. The site's two paymasters are named in its texts (personal, paid) next to their address; any other paymaster is shown by its address only. |
call-decode.js | DeFi calls in plain words for UP Wallet's request window, decoded by function selector: Uniswap's and Aerodrome's Universal Router (v2, v3 and v4 swaps, Permit2, wrap, fees), KyberSwap, LI.FI swaps, Across bridge deposits, Spark's savings vaults and PSM, Aave v3 (Pool supply, withdraw, borrow, repay, and the native-currency gateway) and Aave v4 (supply, withdraw, borrow, repay and collateral at the Spokes it lists, also inside their multicall; amounts in the reserve's raw units), and CoW Protocol orders (setPreSignature: the order is read from CoW's public API and used only if its EIP-712 hash, owner and validity match the orderUid, otherwise the window says it could not be verified). For each call it shows what goes in, what comes out at least and who receives it, in red when a recipient is not the UP; for a bridge, the destination network and whether the UP already exists there. A call it cannot decode cleanly falls back to the page's generic view. |
abi-decode.js | Last step of UP Wallet's decoding, for calls no specific decoder recognises: the contract's verified ABI from the network's Blockscout explorer (public API, no key; a proxy is read through its implementation; kept in the browser for 7 days) gives the function's name and its parameters with their names. It does not say what the call does, and the request window says so; a recipient-like parameter (to, recipient, receiver, and refund addresses such as refundAddress…) that is not the UP is in red. A multicall(bytes[]) to the contract itself is opened: each inner call is decoded with the same ABI, recipient check included. The recipient row names the contract as the explorer does: its public tag when Blockscout has one, otherwise the verified source's name (chosen by whoever verified it, and said so), also when the explorer gives the address no name (as for some contracts on Arc). The same name follows the address in the request summary and in an approval's spender (for a token, the symbol it declares); plain accounts are not looked up. A recipient warning inside a multicall says which inner call it is about. Enabled on Base, Arbitrum One and Arc (their Blockscout explorers); a contract not verified there stays unrecognised. |
token-image.js | Token and NFT thumbnails for UP Wallet's "Every network" view, with the image rule of AUDIT N-1: loaded by themselves only when inline, on IPFS (through the site's gateways) or on Alchemy's image CDN; an image on another server, chosen by the token's creator, would tell that server who looks at the UP, so its thumbnail is dashed and loads on a tap. LUKSO tokens (LSP7 / LSP8) take the icon from their LSP4 metadata, used only when its keccak256 hash matches. Also used for the token chosen in the Send panel and for the UP's profile picture in the menu's card (from its LSP3Profile, read on LUKSO, else on the chosen network, same hash check). |
lifi-topup.js | The operator's top-up from USDC on Base (up-gas-relay-admin.html, section 3c). The operator chooses the network, the paymaster (personal or public) and a number of operations; the page asks LI.FI's public API for a quote (USDC on Base in, the network's own currency out, bridged when needed, only routes without a call on arrival) and uses it only if the transaction is on Base, to LI.FI's contract, with no value, and its calldata itself names the cassa as receiver and that network as destination. The cassa signs on Base the approval of the exact USDC amount, then the transaction (quoted and checked again just before); the arrival is followed through LI.FI's status, and the page switches the wallet back to that network and prepares the paymaster top-up for the amount the operations need, through the usual checks of section 3 or 3b: the cassa's third signature (if it does not start, the amount stays written there). No key and no funds on the server. |
op-cost.js | About how much one gas-relay operation costs on each chain, in its own gas token: averages of the operations the sponsor paymaster really paid (Polygon: an estimate). The operator's page and the relayer's monitor count each paymaster deposit in operations ("≈ 340 operations") and flag a deposit for fewer than 100 operations (public paymaster) or 20 (personal one). Approximate: fees change, and the table is updated now and then. |
usd-price.js | USD value of a chain's gas token, from Chainlink price feeds read on that chain through the same RPC (no external API). Each feed is used only if its description() is the expected pair; a price older than 24 hours is marked "not up to date"; on Arc the gas token is USDC. Loaded by the operator's page up-gas-relay-admin.html (deposits and relayer balance with their USD value; on a chain without a cost per operation in op-cost.js, deposits under 10 USD for the public paymaster and 1 USD for the personal one are flagged) and by UP Wallet's "Every network" view (the UP's own balances only), and used by the relayer's monitor and tools/relayer/balances.js. The public pages show no paymaster figures. |
sign-check.js | Shared box shown while MetaMask asks to confirm a transaction, on every page that sends one (Deploy, Backup, Test, Identity, NFT receiving, Publish implementation, multichain deploy, the gas pages). It lists what MetaMask must show (network, signing account, recipient with its name, value, the function called, start and end of the data, and what the UP does inside a Key Manager call), decoded by the page, to compare before confirming. The relay pages show the same kind of box for the message to sign (gas-relay-client.js). UP Wallet has its own request window. |
backup-check.js | Shared, read-only check of whether a UP has a backup controller on one network: at least two controllers with the same permissions, including ADDCONTROLLER and EDITPERMISSIONS (the ERC4337 bit is ignored; the EntryPoint and the Universal Receiver Delegate never count). The Test and UP Wallet pages use it to show a small alert, only when the backup is missing, linking to the Backup page (up-backup.html) with the same network and UP; the Backup page uses it to read the controller list. |
deploy-check.js | Shared checks of the Deploy and Verify pages (AUDIT section 9, M-4): before a deploy, the calldata must initialize the profile the standard LUKSO way and fund it as expected (the CREATE2 address does not cover these); on a deployed profile, the UP must be owned by its Key Manager and the Key Manager must control that UP. |
up-multichain-deploy-v2.html | Deprecated — do not use. Initial test page of the deploy flow, used on localhost before the public tools went online. Kept for reference only: all its actions are disabled, it shows a warning banner and is marked noindex. Use up-deploy-public.html. |
theme.js | Light / dark theme switch for every active tool page (button next to the language one). The pages' colours are CSS variables; the light theme redefines them. The choice is kept in the browser (localStorage); the default stays dark. |
asset-list.js | Shared, read-only list of what a UP holds on one network: native balance; LSP7/LSP8 from the UP's own LSP5ReceivedAssets, with balances and token IDs read from the chain; ERC-20, ERC-721 and ERC-1155 from an indexer (Alchemy when config.js has a key and covers the network, otherwise Blockscout's public API, LUKSO's and Arc's explorers included, also when Alchemy refuses; on Arc the ERC-20 interface of the native USDC is not listed again, since the native balance shows it). Indexer rows are only as complete as the indexer; spam flags are the indexer's. Indexed ERC-721 / ERC-1155 are read again on the chain (ownerOf, or the balance of each token ID) and left out when the UP no longer holds them, since an index can lag behind a transfer; the pages say how many were left out. Used by the Identity page. |
up-identity.html | Identity. Reads a UP's LSP3 profile (name, description, images, links, tags) on the chosen network and on LUKSO: decodes the LSP2 VerifiableURI (current and legacy formats), downloads the file and images through LUKSO's public IPFS gateway (ChainIntegrate's node and ipfs.io as fallback), checks its keccak256 hash before showing anything, and says whether the network's profile is identical to LUKSO's, older (a redeploy copies only the creation data) or missing. Also lists the UP's controllers on that network, with their roles and the backup status (backup-check.js), and what the UP holds on both networks (asset-list.js), with token and collection images (LSP4Metadata for LSP7/LSP8, hash checked; the indexer's image otherwise). Reading needs no wallet. Section 6 aligns the network's profile with LUKSO's: one Key Manager transaction setData(LSP3Profile, <LUKSO's value>), signed by a controller with SUPER_SETDATA (or SETDATA with the key allowed), read again before signing, simulated and verified after confirmation; an explicit note that this is ChainIntegrate's reading of the ERC725Y data. |
up-crosschain-guide.html | Step-by-step guide (EN/IT): how the address is derived, how to find your calldata, how to check the controller, how to deploy and operate, and why to add a backup controller (losing the genesis key, not theft). |
up-wallet.html | Experimental. UP Wallet: the UP's wallet on LUKSO and on every network where it is deployed, with the same address, doing there what the UP extension does on LUKSO (see and send what the UP holds, use dApps). Technically, a WalletConnect bridge that lets a UP act as the account on any dApp, on any network where it is deployed (built-in list or custom RPC, one network at a time). As soon as network, UP and MetaMask are set, it checks that they are compatible: RPC and wallet on the same chain, UP and Key Manager deployed, the MetaMask account is a controller, and which of contract calls, value transfers and signatures its permissions allow. It also reports whether the UP can receive ERC-721 / ERC-1155 NFTs sent with safeTransferFrom (this needs an LSP17 extension on the UP, with code on that network; up-nft-receiver.html sets it up). The check runs again on any change and before every request. Transactions are decoded where possible (token transfers and approvals, with a strong warning on approvals; deposits into and withdrawals from ERC-4626 vaults, and Morpho's own VaultBundlesV1 calls (deposit, withdraw, move between vaults, with any referral fee shown in red), with the vault and its asset read from the chain, the vault's own estimate of the other side, and a red warning when the shares or the assets would go to another address; a few contracts deployed at the same address on every chain, such as Permit2, Seaport, LI.FI (Diamond and Permit2 Proxy) and 0x AllowanceHolder, are named when they have code on the chosen network; swaps through Uniswap's and Aerodrome's Universal Router, KyberSwap and LI.FI, Across bridge deposits and Spark's savings vaults and PSM, with what goes in, what comes out at least, the recipient and, for a bridge, the destination network (call-decode.js); on Base, Arbitrum One and Arc, any other call to a contract verified on the explorer shows its function and named parameters (abi-decode.js); on hup.social's contracts on Base, Arc and LUKSO, posts, replies, edits, likes and poll votes are decoded, and follows through LUKSO's LSP26 Follower System; hup.social's chat sign-in message is recognised and checked: its site, the UP it names and its time; on Avalanche, BENQI's lending deposit and liquid staking, Aave's position manager and AVAX collateral deposit (pro.aave.com) and Yield Yak's strategy deposit). An unrecognised call can be copied or e-mailed to the maintainer with all its data (the full text is also copied, in case a mail program cuts a long link). The raw data of a decoded call is shown on request, so the request reads well on a phone, simulated, wrapped into KeyManager.execute(UP.execute(...)) and sent only after explicit confirmation in a modal window that shows every check and detail of the request. Message signatures work as in the Basenames demo (ERC-1271, verified on the UP before returning), with warnings for opaque data, Permit/Permit2, orders and sign-in messages for another domain; a sign-in, a Permit or an EIP-3009 transfer authorization made out to another account than the UP is flagged in red, and every EIP-3009 TransferWithAuthorization is shown as a signed transfer with its amount and recipient. A token whose transfer / approve answers false in the simulation is refused before the confirmation window. Names, symbols and URLs that come from dApps, tokens or typed data are shown on one line, without control characters, so they cannot add lines of their own to the page's messages. Always rejected: eth_sign and legacy formats, any 32-byte personal_sign (a hash: where the UP has the gas relay set up it would authorize spending, on any network, AUDIT W-H1), contract creation, transactions to the UP itself, its Key Manager or the gas relay's contracts, requests on another network. A request to switch network is refused (4001) and the dApp is told the session's network; for a dApp known to prepare its transactions through its own node (Aave Pro on Arc), the connection checks that node and, when it does not answer web pages, says that the block is on the dApp's side. Panel 6 sends from the UP without a dApp, through the same window, checks and simulation: the network's currency, ERC-20 / LSP7 tokens and NFTs (LSP8, ERC-721, ERC-1155; the UP's ownership of the token ID is checked on the chain), to an address or to a Universal Profile found by name in LUKSO's profile index. Its balances list (asset-list.js) shows what the UP holds; tapping a row chooses it, and the chosen token is shown with its image. The page opens as a menu: a card with the UP (its profile picture and name), its network and its state, a "⇄ UP" chip that switches among the UPs saved on this device (each UP set in panel 2 is saved, addresses only, never sent anywhere; more can be added by address or by name from LUKSO's profile index; switching runs the check again and closes the WalletConnect sessions after a confirmation, since each dApp is connected to one UP), with two chips that open a small window each: simulation or real sending, and who pays the gas (the site relayer or the controller; the request summary says it too). When the site relayer cannot take an operation (more than 2,000,000 gas, above the paymaster's cap per operation, low deposit, relayer not ready), the request is not refused: the window shows why and offers to pay the gas with the controller, with the estimated cost and the controller's balance; a refused request gives the dApp the same reason. The last error of a request stays visible in the short message log until the next request or a tap. Buttons for Send, Receive (the UP's address as a QR with the network's chain id, and a link to its identity page to share), Every network (read only: what the UP holds on every main network where it exists, two networks read at a time, with an estimated total in dollars where the price is known: the network's currency from Chainlink and Circle's native USDC by its contract address; other tokens are listed without a price, spam is not counted, each line with the token's image where one is available (token-image.js); positions in protocols are read from the chain: ERC-4626 vault shares (Morpho, Spark) with the underlying amount they are worth, Aave v3 aTokens as deposits, and Aave v4 supplies kept inside the Spoke (not tokens in the UP), priced when the underlying is USDC; and the networks where the UP does not exist or that did not answer are named), Connect a dApp, Activity, Settings and the explanation. Networks are chosen from buttons with their logo, with a green dot where the UP exists (its code read on each main network). The warnings open in a window at start, until accepted. "Full view" in Settings shows every panel on one page, as before. Needs config.js like the demo below. The page remembers, in the browser, the "Only simulation" choice and the last UP used; the site relayer is ticked by itself where it is available (it can be unticked); "Every network" gives a dollar value to the network's currency, Circle's USDC and the euro stablecoins EURe and EURC (Chainlink's EUR / USD rate), and says which index listed the other tokens. |
up-wallet-app-privacy.html | Privacy policy of the UP Wallet Android app (IT/EN, ?lang=en opens it in English): what stays on the phone, which services the app talks to and what they see, what the site's relayer logs and for how long, the app's permissions, GDPR rights. |
up-nft-receiver.html | Experimental. Lets a redeployed UP receive ERC-721 / ERC-1155 NFTs sent with safeTransferFrom (marketplace purchases). The three receiver callbacks go to LUKSO's official LSP17 extension ERCTokenCallbacks (0x082d49D8487d2ed2527440c7879C66d850daaBc5, @lukso/lsp17-contracts, published by LUKSO on Base, Polygon, Arbitrum One, Avalanche and many other chains). supportsInterface goes to ChainIntegrate's contracts/NFTReceiverExtension.sol (0x7F68…C03e), which declares exactly ERC-165, IERC721Receiver and IERC1155Receiver: ERCTokenCallbacks also declares the LSP17Extension interface, which a UP is not. Where LUKSO's extension is missing (LUKSO mainnet today), ChainIntegrate's is used for everything; if that is missing too, the page links to up-publish-implementation.html, where anyone can publish it with any wallet, without a UP. Both are checked by code hash on the network. A UP already set up with ChainIntegrate's extension keeps working; the page offers to move its callbacks to the official one (one transaction, optional). Registration is one atomic KeyManager.executeBatch: the controller grants itself ADDEXTENSIONS / CHANGEEXTENSIONS if missing, sets the LSP17 keys, and restores its exact original permissions. The page shows the plan and simulates it before signing, and verifies the result. See contracts/README.md. |
up-gas-relay.html | Experimental. Gas paid by the site: the user's page to prepare a UP. (2) A read-only configuration check that runs by itself, without a wallet, and says what is missing and where to do it: EntryPoint exactly 0x500, extension, controllers, and at the end whether the site pays this UP's gas (operator's allowlist, or subscription with its balance; otherwise a pointer to up-subscribe.html). (3) The UP's controller publishes LUKSO's Extension4337 if missing and sets up the UP in one atomic KeyManager.executeBatch (extension for validateUserOp, EntryPoint as a controller with SUPER_CALL and SUPER_TRANSFERVALUE but no SETDATA, 4337 permission for the controller, other permissions unchanged); one more transaction turns 4337 off again. Plans are shown and simulated before signing, results verified. See contracts/README.md. |
up-gas-relay-admin.html | Experimental, operator's page (not linked from the public pages). With the cassa in MetaMask: (3) publishes contracts/UPPaymaster.sol at its deterministic address, funds it, sets the cost cap; (3b) publishes and manages contracts/UPVerifyingPaymaster.sol, the sponsor paymaster (top up, signer, cap, withdraw, "Stop now"); (3c) tops up either paymaster from the cassa's USDC on Base, for a number of operations, through LI.FI (lifi-topup.js); (4) the allowlist, plus the same UP setup as the user page; (5) a test operation through the site relayer; (2) the full configuration check, paymasters included (the Key Manager's target(), ownership transfers in progress). Amounts are repeated with the network's currency and their dollar value before the wallet opens; setup and revoke plans list what the transaction writes, decoded from its data, and replacing another validateUserOp extension needs an explicit acknowledgement (it is put back when 4337 is turned off). |
gas-relay-page.js | The code of the two gas relay pages above. Each page says which one it is (window.GAS_PAGE) and carries its own texts; the user page has no admin controls. |
up-subscribe.html | Experimental, beta. Subscription and top-up of the sponsored gas service. The user pays 5 USDC (Circle-native, on Base, Arbitrum One, Polygon, Avalanche or Arc) from the UP to ChainIntegrate's UP with an operation whose gas the site pays, and gets one USDC balance valid on every network; each operation the site pays takes that network's price (read from the service). As soon as a network and a UP are entered, it shows the UP's balance or subscription status, without a wallet. It then checks, read-only: the UP exists on the network (otherwise a link to the Deploy page), its 4337 setup (otherwise a link to up-gas-relay.html, with why it is needed), the UP's USDC. The USDC contracts, the receiving UP and the published price list are written in the page: if the service answered other values, nothing is signed. The e-mail goes only to the service, for the activation and the low-balance alerts (2.5, 1 and 0.5 USDC). The operator activates each payment after checking it; there is no automatic charge. While the service does not accept subscriptions, the page says "not open yet". The service is in beta: the page says that it may change or be suspended and that the final terms of service are not published yet, so only small amounts should be paid. |
up-walletconnect-basenames.html | Deprecated — closed experiment, no longer maintained. Kept for reference only: all its actions are disabled and it shows a warning banner. Use up-wallet.html. Originally: A WalletConnect bridge that lets a UP redeployed on Base act as the account on Basenames (base.org/names): the dApp sees the UP address, and the registration transaction is wrapped into KeyManager.execute(UP.execute(...)) and signed by the controller, so the name is owned by the UP. It only accepts Base and Basenames registrations and has a simulation-only mode. Message-signing requests (personal_sign, eth_signTypedData_v4) are shown in full and signed by the controller only after explicit confirmation; the UP validates them through ERC-1271 (the controller needs the SIGN permission), and the page checks isValidSignature on the UP before returning the signature. eth_sign and legacy formats are always rejected. Tested on Base mainnet: a name was registered to a redeployed UP, including the primary-name signature. Needs a WalletConnect (Reown) Project ID in config.js on the server (see config.example.js). |
tools/decrypt.js | Advanced, offline only — not published on the website. Node.js helper that decrypts a secret from a UP browser-extension backup (AES-256-GCM, PBKDF2-SHA256). See tools/README.md. |
tools/csp.js, .github/workflows/csp.yml | The pages' Content-Security-Policy: tools/csp.js writes in each page a <meta> policy with the SHA-256 hash of its inline scripts; run it after changing one. The workflow runs tools/csp.js --check on every push and pull request. See "Security headers" below. |
tools/relayer/ | Experimental, server-side — not published on the website. The gas relayer service behind every "Pay the gas with the site relayer" option (UP Wallet, subscription page, the operator's test operation), and its hourly monitor (configuration of every watched UP and paymaster, deposits, relayer balance, sudden drawdowns, e-mail on change): Node.js, runs from its own clone outside the web root, reached through the web server at /relay/. See tools/relayer/README.md. The signing service of the sponsor paymaster is in a separate, private repository. |
contracts/ | Our contracts (NFTReceiverExtension, UPPaymaster, UPVerifyingPaymaster) and LUKSO's Extension4337 as published: sources, exact compiler inputs, addresses, code hashes and source verification status. See contracts/README.md. |
vendor/ | The WalletConnect bundles (the UP Wallet's, and the client used by the tool pages to read the UP's address from LUKSO's Universal Profiles app and to connect MetaMask on a phone) and the QR code library, pinned, loaded with Subresource Integrity, telemetry off, and documented. See vendor/README.md. |
config.example.js | Template of the site's config.js (WalletConnect project ID, Alchemy key). |
guide-assets/ | Screenshots used by the guide. |
banner.png, logo.png, favicon.ico | Branding for the pages. |
AUDIT.md | Full security, privacy and bug audit report. |
WALLET-BACKLOG.md | Changes to UP Wallet waiting for the next batch: they are made together, in one pull request, followed by one app release. |
SECURITY.md | How to report a vulnerability privately. |
CONTRIBUTING.md | What contributions are accepted, and how to propose them. |
THIRD_PARTY_NOTICES.md, licenses/ | Third-party code included in the repository, and the license texts. |
AUDIT.md), and the whole project every six months by two LLMs of different providers; the external reviews of 2026-10-26 and 2026-10-29 covered the whole project, the phone key and then the browser extension included (AUDIT.md §15, §17). A professional audit is planned for the gas relay (the paymasters, Extension4337 and the ERC-4337 flow) when the paid service has significant users or funds: that is where third parties' money would be. The rest is open source, used at one's own risk.| AUDIT.md §12 |
| 2026-10-12 | Re-audit of the whole system: toolkit, signing service and the Android app (AI-assisted) | One High in UP Wallet (W-H1: the 32-byte signature refusal was checked only on the chosen network), fixed the same day; Low items fixed or explained; previous findings confirmed fixed; contracts unchanged. | AUDIT.md §13 |
| 2026-10-19 | Fixes of every item still open (rev. 12) | Full Content-Security-Policy (N-3); the site's files outside the pages verified as not served (M-08); WalletConnect telemetry off and bundles under SRI (W-tel); the hardening backlog of 2026-10-02 (L-8, I-1 to I-7) closed. Still open by design: M-1 (paymaster gas up to the cap per operation, bounded by the caps) and the periodic RPC check (L-07). | AUDIT.md §9, §12, §13 |
| 2026-10-26 | External review of the whole system: toolkit, signing service, Android app 0.9.2 with the phone key (AI-assisted, rev. 13) | No Critical or High. Two Medium (PK-1: the phone's address from a link on the Backup page; WEB-1: anti-framing headers not committed) and the Low items (the phone key's own 32-byte refusal, wording of its permissions, its fingerprint prompt, three in the signing service, SRI on the QR library) fixed the same day. | AUDIT.md §15 |
| 2026-10-29 | External review of the whole system, four repositories: toolkit (page 0.11.0), signing service, Android app 0.9.7, the new browser extension 0.1.7 (AI-assisted and in-depth, rev. 14) | No Critical, High or Medium; every earlier finding verified fixed in the code; contracts unchanged. Three Low accepted with their reasons (EXT-1, REL-1, CSP-1), six Info. | AUDIT.md §17 |