diff --git a/CHANGELOG.md b/CHANGELOG.md index 11758db..b5f7a52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixed - **A TELA INDEX can be updated on the simulator again.** `update-index` refused every attempt with *"Your wallet is not the owner of this INDEX"*, including from the wallet that had just installed it. The check compared the author string stored in the INDEX against the address the wallet renders — but those two strings come from two different renderers. The stored author is what the contract's `address()` returned, which is the DVM's `ADDRESS_STRING`, which builds it with `rpc.NewAddressFromKeys` and leaves `Mainnet` true; consensus cannot depend on which network a node thinks it is on, so a contract records `dero1...` on every chain, the simulator included. walletapi renders the same key through the wallet's network flag and says `deto1...` there. A DERO address is bech32 — the prefix names the network and the checksum is computed over it — so both halves differ and the compare read one wallet as two, always. Ownership is now decided on the decoded public key. The contract's own owner gate was never affected (it compares `address()` to `address()`), and neither was mainnet, where both renderings agree. The same correction applies to the ownership flag reported by INDEX info, which read `false` for the owner's own INDEX on the simulator. +- **A contract deployed by a dApp is signed by the wallet that dApp is connected to.** A dApp can deploy by sending `transfer` with an `sc` field, the way Engram and the TELA CLI accept it. HOLOGRAM handed that to the generic install path, which decided the signer again on its own: in simulator mode it took wallet #0 regardless of which wallet was open, while `GetAddress`, `GetBalance` and `scinvoke` on the same connection all answered for the open wallet. A contract that records its deployer — `STORE("owner", SIGNER())`, the ordinary pattern — therefore recorded a wallet the dApp had never connected to, and refused its own creator on the next call. The deployment is now signed by the wallet the call already resolved. The primary-wallet rule it replaced was justified by funding, but on the simulator every registered wallet is credited the same amount and none of the pre-seeded wallets is premined, so wallet #0 held no advantage; off simulator the rule never applied. The Studio deploy screen and the simulator developer deploy now resolve their signer the same way every TELA deployment already did: the open wallet, with the primary as a fallback when none is open. +- **A deployment arriving from a dApp no longer freezes the wallet off simulator.** The same handoff called `GetWallet()` from inside a function that holds the wallet manager's write lock for its whole body. `sync.RWMutex` is not reentrant, so that read lock could never be acquired by the goroutine already holding the write lock: the call never returned, the deferred unlock never ran, and every later wallet operation blocked behind it. The install core no longer touches the wallet manager at all — it signs with the wallet it is given. + +### Changed +- **The approval prompt names the wallet that will sign, and says when a deployment is what is being approved.** A `transfer` carrying `sc` has no destination, no SCID and no entrypoint, so it reached the prompt as an empty request while a contract was about to be deployed under a signature the user could not see. The prompt now shows the signing wallet for every signing request, and announces a contract deployment with the size of the code. ## [1.0.8] - 2026-08-20 diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 5dc57c1..5091189 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -421,6 +421,11 @@ sc_token_deposit: req.params?.sc_token_deposit, sc_token_deposit_scid: req.params?.sc_token_deposit_scid, fees: req.params?.fees, + // A transfer carrying `sc` deploys a contract. It has no destination, no SCID and + // no entrypoint, so without these two the modal shows an empty request while a + // contract is being deployed. The code itself is not surfaced — its size is. + scDeploy: req.scDeploy === true, + scCodeBytes: req.scCodeBytes, }; } @@ -444,6 +449,10 @@ // while approving actually decrypted the wallet and signed a challenge. description: req.description, isSignIn: req.isSignIn === true, + // The wallet that will sign this request. The app holds the wallet, not the dApp, + // so which one signs is the app's to disclose — approving without seeing it is + // approving blind, and a deployment records its signer permanently. + walletAddress: req.walletAddress, // true = the browser vouched for the origin; false = the app named itself originVerified: req.originVerified === true }, diff --git a/frontend/src/lib/components/WalletModal.svelte b/frontend/src/lib/components/WalletModal.svelte index 26696b6..df655b1 100644 --- a/frontend/src/lib/components/WalletModal.svelte +++ b/frontend/src/lib/components/WalletModal.svelte @@ -510,6 +510,29 @@