rotki

rotki.com
rotki

A self-hosted, opensource, privacy-first portfolio tracking and accounting tool for crypto and more. Support for all 3 major Operating systems and docker. The tool focus is on data self-sovereignty.

Crypto Payments Accepted Open Source

rotki Source Code

Author

rotki

Description

A portfolio tracking, analytics, accounting and management application that protects your privacy

#accounting#analytics#bitcoin#blockchain#cryptocurrencies#cryptocurrency-exchanges#cryptocurrency-portfolio#cryptocurrency-portfolio-tracking#ethereum#hacktoberfest#management#management-system#portfolio-tracker#tracking

Homepage

https://rotki.com

Repository

  • LicenseAGPL-3.0
  • Created05 Mar 18
  • Primary languagePython
  • Size513,782 KB
  • Stars3,978
  • Forks755
  • Watchers3,978

Language Usage

Language Usage

Project Health

  • Last commit52 minutes ago
  • Open issues432
  • Latest releasev1.43.2

Top Contributors

Recent Commits

  • Yábir Benchakhtir(20 Aug 26)

    Bump version: 1.43.2 → 1.44.0 (#12971)

  • Konstantinos Paparas(20 Aug 26)

    fix(frontend): ignore keys while an IME is composing The pill filter list acted on Enter and the arrows without checking whether the key arrived mid-composition. An IME confirming a candidate therefore committed a row and closed the list mid-word, and the arrows walked the option list instead of the candidate list. Same guard the send form's token picker got in #12961; this list is the app's other virtualized picker.

  • Yabir Benchakhtir(20 Aug 26)

    Merge branch 'bugfixes' into develop # Conflicts: # docs/changelog.rst # frontend/app/electron/main/create-protocol.spec.ts # frontend/app/electron/main/create-protocol.ts # frontend/app/vitest.config.ts # rotkehlchen/assets/resolver.py # rotkehlchen/chain/arbitrum_one/modules/gmx/balances.py # rotkehlchen/chain/arbitrum_one/modules/thegraph/balances.py # rotkehlchen/chain/arbitrum_one/modules/umami/balances.py # rotkehlchen/chain/base/modules/morpho_blue/balances.py # rotkehlchen/chain/base/modules/runmoney/balances.py # rotkehlchen/chain/ethereum/interfaces/balances.py # rotkehlchen/chain/ethereum/modules/aave/balances.py # rotkehlchen/chain/ethereum/modules/blur/balances.py # rotkehlchen/chain/ethereum/modules/convex/balances.py # rotkehlchen/chain/ethereum/modules/curve/balances.py # rotkehlchen/chain/ethereum/modules/eigenlayer/balances.py # rotkehlchen/chain/ethereum/modules/hedgey/balances.py # rotkehlchen/chain/ethereum/modules/lido_csm/balances.py # rotkehlchen/chain/ethereum/modules/octant/balances.py # rotkehlchen/chain/ethereum/modules/safe/balances.py # rotkehlchen/chain/evm/decoding/compound/v3/balances.py # rotkehlchen/chain/evm/decoding/curve/lend/balances.py # rotkehlchen/chain/evm/decoding/extrafi/balances.py # rotkehlchen/chain/evm/decoding/gearbox/balances.py # rotkehlchen/chain/evm/decoding/giveth/balances.py # rotkehlchen/chain/evm/decoding/hop/balances.py # rotkehlchen/chain/evm/decoding/woo_fi/balances.py # rotkehlchen/chain/optimism/modules/walletconnect/balances.py # rotkehlchen/tests/db/test_history_events.py # rotkehlchen/tests/unit/test_blockchain_balances.py # rotkehlchen/tests/unit/test_price_historian.py # rotkehlchen/tests/unit/test_protocol_balances.py # rotkehlchen/tests/unit/test_tasks_manager.py

  • Konstantinos Paparas(19 Aug 26)

    fix(frontend): keep pinned matching pager in view The pinned bridge and asset-movement panels capped their card list at `calc(100vh - 20rem - <description height>)` and rendered it inside `RuiTabItems`, which sizes itself from its content and hides the overflow. When the guessed chrome allowance fell short of the real one, the tab item was shrunk below its content and the bottom of the panel was cut off. The pager sits outside the scroll area, so it was the part that disappeared: at a 900px viewport it landed 77px past the clip line and only came back into view around 67% zoom. Size the list by the space it actually has instead. The card list is a bounded flex column that fills its host, the pinned branch renders the active list straight into a flex column rather than through `RuiTabItems`, and the viewport cap is left to the dialog, which cannot propagate a height down to its table.

  • Konstantinos Paparas(20 Aug 26)

    ci(sqldiff): cap job and apt install runtime The SQLDiff job declared no timeout-minutes, so it inherited GitHub's default of 360. On PR #12965 a run sat pending for 55 minutes and only cleared as CANCELLED, while every other check settled inside ~15. Step timings over the last 40 runs place the time in the apt install, not in the action: Install required median ~12s, worst success 253s, hung run 3302s SQLDiff action 0-1s every run So the install step gets 10 minutes, roughly 2.4x the worst success, and the job gets 15 as an outer bound. A hang now fails fast and legibly instead of blocking the PR's merge state for six hours.

  • Konstantinos Paparas(19 Aug 26)

    fix(frontend): stop hover hijacking the pill filter list The option list set its highlight from a bare mousemove. The list is virtualized and the arrow keys scroll it, so a row the user never pointed at arrives under a cursor that has not moved, and the browser reports that as a mousemove at unchanged coordinates. Obeying it hands the highlight straight back, so the arrows could not advance past one row and a wheel scroll dragged the highlight along with it. Pointer moves are now taken only when the coordinates actually changed. Same defect and same fix as the send form's token picker in #12961, which is where it was spotted; this list is the other virtualized picker in the app.

  • Konstantinos Paparas(19 Aug 26)

    fix(frontend): hide empty nft section on dashboard The dashboard nft table was gated only on the NFTS module being active, so an account with no nfts still got the section header and an empty table. The liabilities table beside it already gates on its row count. Render the section only once the fetch reports at least one entry, using the collection's `found` count now returned by `useNftData`. The gate lives in the component rather than in `Dashboard.vue` because `NftBalanceTable` fetches its own data on mount, so gating from the parent would prevent the fetch that produces the count. `found` starts at zero and the fetch is not immediate, so this also removes the brief empty table shown while the dashboard loads. When the section is hidden the component root is a comment node and the `id`, `data-testid` and `class` passed by `Dashboard.vue` cannot be inherited automatically, so they are forwarded explicitly instead.

  • Konstantinos Paparas(19 Aug 26)

    build(deps): bump @rotki/ui-library to 2.24.0

  • Konstantinos Paparas(19 Aug 26)

    feat(pill-filter): accept a date bound with no time A period bound typed as a bare date was dropped without a word: the picker only emitted once every segment down to the minute was set, so the filter never saw the value and the pill stayed empty. The two bounds now declare which end of the day an incomplete entry stands for, From taking the start and To the end, so a range given as two bare dates covers the days whole rather than collapsing onto the first instant of the last one. The e2e page object closed the date editor by dismissing the picker's calendar and nothing more. That escape never reaches the field, so only the bound that happened to be blurred by moving to the other one was committed: closing the editor now sends the press that finishes the last bound.

  • Konstantinos Paparas(19 Aug 26)

    docs: sync CLAUDE.md and AGENTS.md AGENTS.md says it mirrors CLAUDE.md. It did not: the two had drifted to 129 diverging lines, so which file an assistant read decided what it was told. Both now carry the union. CLAUDE.md gains the Sourcify ABI lookup, the decoder scope policy, the ActionItem matching rule, the indexer-unavailable fallback, the expanded hex/bytes constants policy, the backend style preferences and the historical balance context. AGENTS.md gains the navigation and meta.nav section. One difference was a contradiction rather than drift. AGENTS.md said the backend "uses pytest with gevent for async testing"; CLAUDE.md said concurrency runs through rotkehlchen.concurrency tasks on threads. The second is correct: concurrency/tasks.py spawns threading.Thread and its docstring describes the module as the seam for the gevent removal, with gevent imports banned via ruff TID251. AGENTS.md now says the same. AGENTS.md also had the historical balance section nested under Testing Strategy, where it does not belong; it now sits with the other backend context. Also points the consolidated Testing section at "Fast checks via pnpm scripts" for how to run a test, which the previous commit moved out of it. The files are now byte-identical apart from the title and the sentence that states the mirroring, so a future divergence is a one-line diff to spot.

  • Konstantinos Paparas(19 Aug 26)

    docs: consolidate the frontend testing strategy Frontend testing was documented in three overlapping places, with four facts stated twice, so an edit to one silently contradicted the other. It now lives once, under Testing in the Frontend Development Guidelines; the Testing Strategy section keeps only the directory layout and how to run e2e. The gap that consolidation exposed is component testing. The guidance was one line, "follow existing patterns", while the coverage split is 86% for .ts against 34% for .vue, and covering every remaining .ts line still falls short of the target. The new section says component tests are mandatory and why, and covers what the old text left out: extract the logic before testing the component, or the spec pins the shape that should have been split; name the seam and test only that; a mount-only test moves the coverage number and proves nothing; unmount what you mount, since a leaked wrapper keeps reacting to a shared module ref and surfaces in later tests. Negative controls are promoted from one e2e bullet about row indices to a general rule, including how to break the right line, what it means when the control passes, and which assertion shapes most often pass for the wrong reason. Two traps that cost real time and were nowhere: createMock proxies every property it was not given to a truthy auto-stub, so an omitted boolean reads as true, and happy-dom reports zero-height elements, so anything driven by measured layout has to be stubbed and verified in the app instead. Adds knip to the pre-push gates. It runs in CI and no local lint script invokes it, so an export used only inside its own file passes everything locally. The coverage figures are dated and point at rotki/rotki#11252 so a later reader re-measures rather than trusting them.

  • Konstantinos Paparas(19 Aug 26)

    feat(frontend): navigate and read the token list Follows the search and windowing work with what the dialog still lacked once it had a list worth browsing. The search field drives the list from the keyboard: arrows move a highlight, enter commits it, escape closes. Typing a symbol and pressing enter is now the whole interaction. The list is virtualized, so every move scrolls as well, and the highlight resets only when the results actually change, not when a balances tick rebuilds the same set into a new array. Keys are ignored while an IME is composing, where enter confirms a candidate and the arrows walk the candidate list rather than the token list. An option is identified by asset AND chain. A native token id is not unique: ETH is the native asset of ethereum, optimism and base alike, so matching on the identifier alone would highlight the wrong network's row with the chain filter on "all", and tick every chain's ETH at once. Hover takes the row index the template already has. Pointer moves are taken only when the coordinates actually changed. Any scroll slides rows under a cursor that never moved, which the browser reports as a mousemove at unchanged coordinates; acting on it stopped the arrows advancing past one row and dragged the highlight along with a wheel scroll. Hovering does not scroll, or the list shifts out from under the pointer that just landed. Opening the dialog highlights and scrolls to the current selection, which also carries a tick, so the active asset is visible rather than somewhere below the fold with enter poised to commit a different row. The search field carries aria-activedescendant and the rows matching ids, so the highlight is announced. Rows show the amount held and its value when there is one, hidden while every amount is zero, which is the case until a wallet is connected. Two rows reading "ASK / GoAsk" are told apart by a shortened contract address, rendered only for a symbol that another row on the same chain also uses, and never for the empty symbol an asset carries before its name resolves. A count above the list says how much is there, and how much of it a search matched. Collectibles are dropped. They cannot be sent through a form that moves a fungible amount, and both the legacy _nft_ identifiers and the CAIP erc721 and erc1155 forms were listed. The default selection is drawn from the display order rather than the raw owned list, so the form no longer opens on an asset nowhere near the top of the list the user then sees. Resolving the symbols that ordering needs is gated on the dialog having been opened: getAssetField goes through the asset info cache, whose resolve() queues a backend mapping fetch for anything it does not hold, so reading the list on mount would cost a request for the entire holding even when the dialog is never opened.

  • Konstantinos Paparas(19 Aug 26)

    feat(frontend): searchable, windowed token picker The send form's token dialog listed every owned asset at once with no way to search it. On one account a single chain carried 83 options, each mounting an icon component plus its own symbol and name resolution, and the only way to find a token was to scroll. Options now come from useTradeAssetOptions, which resolves symbol and name once per asset instead of once per row, narrows to the chain, and matches a search box against symbol, name and identifier, so pasting a contract address finds its token. The list is virtualized with useVirtualList, following ValueSelectList, so only the visible window mounts. Ordering by identifier made the list look random. With no connected address nothing is priced, so the identifier tiebreak added for the spam fix was the only live comparison and the dialog ordered by eip155:1/erc20:0x… The display now falls back to the symbol, which is what the row shows, while native-first and fiat-value-descending still come first and still decide the default. The list holds one height rather than sizing to its contents, which made the dialog grow and collapse on every keystroke once it had a search box. The two watchImmediate blocks that both assigned the default asset are now one watcher. The second also assigned the chain, which re-triggered the first. Options are rendered as buttons rather than clickable divs, so the list is reachable by keyboard, and the empty state distinguishes an empty chain from a search that matched nothing. The header's close button dropped its text-white override. It painted the icon white on the card's white header, so it was invisible in light mode.

  • Konstantinos Paparas(19 Aug 26)

    feat(frontend): search assets by contract address Pasting a contract address into the dashboard or blockchain balances search found nothing: the filter only ever compared name and symbol, even though an address is how you pin down a token whose name you do not know. It is matched now, from four characters up, since a shorter keyword hits a great many hex addresses by chance and buries what was meant. An asset whose whole symbol or name is what was typed is moved to the front of the results. The column sort still decides everything else, so the header's arrow keeps telling the truth and only an exact match jumps it. Filtering also no longer re-tokenizes every balance on every keystroke. The tokens are indexed per asset and rebuilt only when the balances or the resolved metadata change, which on a list of several hundred assets is the difference between a keystroke doing string compares and doing string compares plus a resolve, a lowercase and two allocations per row. Both call sites share one composable now, so the prefetch that keeps the search off a cold cache is wired once rather than in each table.

  • Konstantinos Paparas(19 Aug 26)

    fix(frontend): warm asset cache before searching The dashboard and blockchain asset tables filter on the name and symbol of every balance, but the metadata behind those is resolved lazily by rendering, which only covers the current page. The first search therefore matched nothing and only filled in once the request it triggered came back, while the table read "no search result". Prefetch the metadata of every balance when the list arrives, so the cache is warm before the user types. The prefetch keeps using the select-info cache rather than the app-wide asset info cache: that one is an evicting LRU, and a search touching every balance would churn it. Two supporting changes to the same composable: the queue debounce drops from 1500ms to 200ms, which only needs to outlast one render pass, and the batches of a large prefetch go out together instead of one round trip per 50 assets. A batch now also releases only its own identifiers when it settles. An asset whose metadata is not resolved yet falls back to matching on its identifier instead of being filtered out, so a cold cache degrades to a weaker match rather than an empty table.

  • Konstantinos Paparas(19 Aug 26)

    test(e2e): address history rows by event id, not index `editEvent` resolved its row with `nth(index)` and re-queried that index when clicking, so the click raced the table. The list sorts timestamp DESC and re-renders on every write, and the edit button is only rendered for rows that may be edited (`hideEditAction` hides it for a swap sub-event and for a movement fee). When a re-sort moved such an event into the slot, the locator waited out the full 60s: this is what failed `edit eth block event` on CI. The assertions had the same defect in a quieter form. They also re-read `nth(0)` after saving, so they could report on a different row than the one just edited, and pass because that row happened to contain the expected text. Every edit flow now resolves the row once, before anything mutates the list, and uses that id-pinned handle for both the edit and the checks. The delete flows and the csv-import assertions follow, so no index addressing is left in either spec. The page object sat at 399 of its 400-line ceiling, so rather than shave it, the row concern moves to `HistoryEventRows`: addressing, assertions and actions, with the reason a row is named by its event written down where the next person will look.

  • Konstantinos Paparas(19 Aug 26)

    fix: key the table page title breadcrumb correctly The `:key` sat on the v-if and v-else branches inside the `<template v-for>` rather than on the template itself, and both branches carried the same `index`. The list therefore compiled to `256 UNKEYED_FRAGMENT`, so the entries were diffed by position, and the two branches were indistinguishable to the diff because their keys were equal. Moving the key onto the template compiles the list to `128 KEYED_FRAGMENT` and lets the compiler give the branches their own discriminating `key: 0`/`key: 1`, so switching an entry between the separator form and the current-page form replaces the element instead of patching one into the other. Hoist the bound check into `lastTitleIndex` while here: the branch no longer has to re-test `title` that its own `v-if` already guarantees. The redundant `<template v-else>` around a single span goes too. The component had no spec despite being used by 38 pages, so add one covering the branch this key distinguishes.

  • Konstantinos Paparas(19 Aug 26)

    fix: offer a validator's own withdrawal address The withdrawal-address pill offered only evm accounts that are tracked on ethereum, so typing the address a validator actually withdraws to returned no matches, on the one filter whose whole subject is that address. A validator's withdrawal address is named by the validator, and tracking it as an ethereum account too is a separate decision. Offer every ETH2 account's withdrawal address alongside the tracked ones. Offering an address is only half of it: the bar matches on keywords, and an address with no account behind it has none, so resolveKeywords falls back to the address itself. Without that it would sit in the list and still not answer to being typed.

  • Konstantinos Paparas(19 Aug 26)

    fix: stop the pill bar recursing on a removed field Picking a validator on the eth staking page while a status filter was active crashed the page. The visible error was a TypeError setting '__vnode' on null, but that is fallout: Vue aborts a runaway update loop mid-patch and the next patch dereferences a null el. The first error in the flush is 'Maximum recursive updates' in PillFilterBar. Three behaviours combine to make the loop. disableStatus removes the status field once a validator is picked; the codec skips a filter whose field is gone, so the derived bag loses the status key; pruneInadmissible deliberately keeps a filter whose field vanished, so the state does not. The bag the bar derives and the bag the page holds then disagree with no way to converge, so setFromMatches's self-echo guard never trips and it rebuilds the state on every flush. Since commit always allocated a new array, matches/params changed identity each time, and the watcher that writes them back fires on identity, so the write-back re-entered the rebuild without ever leaving the flush. Compare the pruned state by value and keep the existing array when nothing changed, so a rebuild that changes nothing is not an update. The spec drives the exact path from the crash trace and catches the loop through a warnHandler, reproducing in milliseconds rather than needing a seeded dev instance.

  • Konstantinos Paparas(19 Aug 26)

    fix(snapshots): correct two balance display bugs The conflict-replacement dialog passed a whole BalanceSnapshot as BalanceDisplay's value. BalanceDisplay reads value?.value, but a BalanceSnapshot carries usdValue, so it always rendered 0.00. Partial<Balance> makes the missing field legal and usdValue is only rejected as an excess property on a fresh object literal, so typecheck stayed green. Replaced with AssetAmountDisplay plus SnapshotFiatDisplay, which applies the historic rate these USD values need. The snapshot list bound :previous-value while SnapshotDeltaDisplay declares previousUsdValue, so the change column was a dash on every row. An unknown attribute on a component is not a type error, and the existing spec only asserted the dash for the oldest row, which passes either way. Added a test for a row that has a predecessor.

  • Konstantinos Paparas(18 Aug 26)

    feat(frontend): show typed filter syntax in the bar Nothing on screen said a date or an amount could be written into the bar at all. The narrowing popover now carries a footer of worked examples, one per shape on each side: a lower bound, an upper bound, a span. They are buttons, so the footer demonstrates rather than describes: clicking one puts it in the input and the row it produces appears directly above. It is deliberately not applied, since watching the text become a filter is the lesson, and applying it would add a pill nobody asked for. The footer sits outside the scroll area, because a hint that scrolls away is one you must already know about to find. The examples are literal and never translated: `after` and the spaced ` - ` separator are what the parser accepts, so a translated example would be one the user copies and the bar then refuses. `before` needs its own chip for the same reason, as its only other route was reading it off a bare date's result rows, which are labelled with the translated operator. Only the lead-in is translated. The date is rendered in the user's own format, on a day past the twelfth so the field order cannot be misread, and at local midnight so the formatter does not append a time of day nobody asked about.

  • Konstantinos Paparas(18 Aug 26)

    feat(frontend): narrow by value type keywords A period field is labelled "Period", so `date`, `time` and `when` found nothing at all. Keywords are declared per value type rather than per field, since `>100` and `after 15/01/2024` read the same on every table and no table should have to restate them. A keyword hit ranks as a substring match, never a prefix one, so a visible label always wins. A field whose `matchesTyped` claims the query is now offered as a guidance row at a rank below every real match, so a part-written date returns the field instead of the empty list that reads as "this cannot be typed into". It is suppressed once the query reads as a whole filter, where the filter itself is the better answer. `syntaxExamples` collects what to advertise for the fields on offer: a table with no amount field must never suggest `>100`.

  • Konstantinos Paparas(18 Aug 26)

    feat(frontend): read written amount bounds The bar could only read an amount written with a symbol, while the rows it offers for one are labelled "greater than 100": typing back what the row said did nothing. Amount bounds now also accept the words, with "than" optional, matching the operator words a date has always taken. A query heading for a filter it does not yet spell parsed to nothing, which the bar could only show as an empty popover. `matchesTyped` is the half-written counterpart of `parseTyped`, so `after`, `>` and `15/01` can be answered with the field rather than with nothing. Both stay narrower than "any text": a bare number belongs to the amount fields and `1.5` must not read as half a date, and `to` is the span separator as well as the tail of `up to`, so a span is told apart by always leading with its lower bound.

  • Konstantinos Paparas(19 Aug 26)

    fix: keep spam tokens out of the send form's default asset The onchain send form opened with HEX preselected. Two things had to be wrong for that, and both live in the send flow itself. useTradableAsset applied no ignore filter at all. It kept only EVM chains the connected wallet supports and non-zero amounts, and relied entirely on the shared balances store having been scrubbed by removeIgnoredAssets. A "spam" asset in rotki is just one the backend put on the ignored list, so anything that scrub missed stayed in the selector. Both collectors now skip ignored identifiers, read from the assets store, so the filter no longer depends on another store's cleanup having run first. The default is list[0], and the list was not always ordered. With an address the sort is native first then fiat value descending, but zero amounts are dropped before it, so on a chain whose native balance is zero the native tiebreak never fires and a priced spam token floats above real holdings. With no connected address the list was returned unsorted and unpriced, leaving the default at raw Object.entries key order. The comparator is now extracted, gets an identifier tiebreak so an unpriced list still has a stable head, and is applied to the no-address branch too.

  • Konstantinos Paparas(19 Aug 26)

    fix(frontend): guard typed amounts against throws Since bignumber.js 11 the constructor throws on a value it cannot read, so every free-text amount field was one keystroke away from an exception: inside a computed it took the render down, inside a handler it silently dropped the action. parseNumericInput reads a field into a BigNumber. Without a fallback an unusable value comes back as undefined and the caller has to answer for it; with one, the result is a number it can use. A field being typed reads as zero, while a save refuses rather than writing a nought nobody entered. Also fixes two defects the parse was hiding: the snapshot balance dialog saved an empty amount straight into a throw, and the asset-movement matching menu wrote NaN seconds when its time range was cleared.

  • Konstantinos Paparas(19 Aug 26)

    Add job timeouts to the nightly and release builds (#12954) * ci(dev-builds): add job timeouts to the nightly build Every job inherited GitHub's 360-minute default. macOS x86_64 hangs intermittently in PyInstaller's codesign step and sat idle for the full 6 hours in 7 of the last 20 nightly runs, holding a shared runner that was doing no work. Limits are set from the observed maxima of successful runs with roughly 2x headroom, so a hang is cut loose early instead of occupying a slot until the default cap. * ci(release): add job timeouts to the release build Same gap as the nightly: no job declared a timeout, so all of them inherited GitHub's 360-minute default. The release macOS job runs the same PyInstaller codesign path that hangs on the nightly, and a stalled release is worse than a stalled nightly. Release builds run without the dependency cache on purpose, so they are slower and more variable than the nightly ones and the limits are sized off release history rather than reused. macOS gets 120 minutes against a 26-58 minute observed spread.

  • Konstantinos Paparas(19 Aug 26)

    fix: search rule addresses by name, not just hex The address picker in the "skip chains and addresses" rule dialog is a RuiAutoComplete with key-attr and text-attr both set to `address`, and no custom filter, so the library default only ever matched the raw address. The rows themselves show something else: AccountDisplay renders the alias resolved by getAddressName (address book entry, ENS, account label) and falls back to the address only when there is none. On a real account most rows read as `yabir.eth` or `compound`, and typing what you see returned "no data". Fold the account label and the resolved alias name into the option's searchText (which was built but never read) and pass an explicit filter that matches it, so the picker is searchable by everything it displays. The chain picker was already fine: it uses text-attr="name".

  • Yábir Benchakhtir(18 Aug 26)

    Improvements on matching with socket decoded txs (#12949)

  • Konstantinos Paparas(18 Aug 26)

    fix: keep the accounts table honest after a delete The delete path patched the accounts and balances stores by hand and never reconciled, so anything wrong in that local state was permanent. Two defects followed from it. The removals returned Promise<void> and swallowed their Result after notifying, so the caller could not tell a failed delete from a successful one and dropped the row either way, while the account still existed on the backend. They now return the outcome, and the local removal is applied only when it succeeded. A group deleted chain by chain keeps the chains whose removal failed instead of dropping the whole row. The reported symptom was a race: the periodic balance tick walks every chain, and a walk already in flight answered with a pre-delete snapshot that updateAccounts wrote back wholesale, resurrecting the account with nothing left to correct it. A local removal now bumps a per-chain revision, and a read drops its write when the revision moved while it was in flight.

  • Konstantinos Paparas(18 Aug 26)

    chore(frontend): drop useRefPropVModel Its last callers are gone. Each turned out to be one of three things rather than a need for the helper: a shape the inputs could not hold, which is a mapping; a field of a payload a component had no business taking whole, which is a prop; or a choice that replaces the state rather than editing it, which is a handler. What it offered was writing a field into an object without saying which object it belonged to, and it addressed that field through a computed key, so the compiler could not say either.

rotki Security

6.7/10

Repo Security Summary

Updated 27 Jul 26

  • Maintained10/10
  • Code-Review2/10
  • CII-Best-Practices0/10
  • Dangerous-Workflow10/10
  • Security-Policy0/10
  • Token-Permissions10/10
  • License10/10
  • Binary-Artifacts10/10
  • Branch-Protection8/10
  • Signed-Releases0/10
  • Packaging10/10
  • SAST10/10
  • Fuzzing0/10
  • Pinned-Dependencies9/10

rotki Website

Website

rotki

rotki is an open source portfolio tracker, accounting and analytics tool that protects your privacy.

Redirects

Does not redirect

Security Checks

All 65 security checks passed

Server Details

  • IP Address136.244.105.88
  • Hostname136.244.105.88.vultrusercontent.com
  • LocationAmsterdam,Noord-Holland,Netherlands (Kingdom of the),EU
  • ISPVultr Holdings LLC
  • ASNAS20473

Associated Countries

  • USUS
  • NLNL

Safety Score

Website marked as safe

100%

Blacklist Check

rotki.com was found on 0 blacklists

  • AntiSocial Blacklist
  • Artists Against 419
  • Badbitcoin
  • Bambenek Consulting
  • CERT Polska
  • CoinBlockerLists
  • CRDF
  • CryptoScamDB
  • EtherAddressLookup
  • EtherScamDB
  • Fake Website Buster
  • MetaMask EthPhishing
  • NABP Not Recommended Sites
  • OpenPhish
  • PetScams
  • PhishFeed
  • PhishFort
  • Phishing.Database
  • PhishStats
  • PhishTank
  • Phishunt
  • RPiList Not Serious
  • Scam.Directory
  • SecureReload Phishing List
  • Spam404
  • StopGunScams
  • Suspicious Hosting IP
  • ThreatFox
  • ThreatLog
  • TweetFeed
  • URLhaus
  • ViriBack C2 Tracker

Website Preview

Website preview

rotki Reviews

More Secure Budgeting

About the Data: rotki

Change History

Edit rotki Data

You can edit rotki's entry in this section of awesome-privacy.yml by submitting a PR to our GitHub repo.
Note that some of the information shown above has been aggregated from external sources, a list of these can be found data documentation.

Origin Data

Modify Data

API

You can access rotki's data programmatically via our API. Simply make a GET request to:

https://api.awesome-privacy.xyz/v1/services/rotki

The REST API is free, no-auth and CORS-enabled. To learn more, view the API Docs or read the API Usage Guide.

Share rotki

Help your friends compare Secure Budgeting, and pick privacy-respecting software and services.
Share rotki and Awesome Privacy with your network!