Search

Bitcoin Transactions

Large Charts

Explore bitcoin transactions and their blockchain structure.

Bitcoin Transactions
View live example →

Blockchain transactions are often fast-paced and complex.

This demo shows bitcoin transactions and entity resolution.

We can use a graph to spot interesting patterns and activity that would normally be hidden in an unintelligible list of anonymous transactions.

For more information on blockchains and bitcoin transactions, see our Visualizing Bitcoin blocks blog post.

Blockchain Data

Each transaction is linked to nodes representing its inputs and outputs. Bitcoin transactions are public but anonymous.

Users commonly generate a new address for every transaction, but this is not always the case. As it is more convenient and some users are indifferent to anonymity, around half of the addresses in a typical block are reused.

Identical addresses are likely to be from the same wallet, and so we can group transaction inputs and outputs by address to see what activity that address has been involved with.

Demo Views

Each view guides you through the data, looking at both typical and more unusual transactions. Transaction activity is summarised in the time bar below the chart.

This data is a subset of block 611900.

Key functions used:

import KeyLines from "keylines";
import { data } from "./data.js";

let chart;
let comboIds;
let graph;
let timebar;

const currentViewState = {
  index: 0, // tracks currentViewState
  itemInfo: () => {}, // shows rhs info
  stateTransition: false, // flag to override timebar change event during view changes
};
// Text of differents views
const views = {
  0: document.getElementById("view0"),
  1: document.getElementById("view1"),
  2: document.getElementById("view2"),
  3: document.getElementById("view3"),
};
// Text between buttons
const viewEl = document.getElementById("view");
// State chage buttons
const button = {
  next: document.getElementById("next"),
  prev: document.getElementById("prev"),
};

// Generates and renders the rhs information text
function getSelectedItemInfo() {
  const currencySymbols = { btc: "₿", usd: "$" };
  const contentEl = document.getElementById("content");
  const headerEl = document.getElementById("header");
  function format(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  }
  function truncate(string) {
    return string.substring(0, Math.min(25, string.length)).concat("...");
  }
  function addCommas(string) {
    return string.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  }
  function highlight(float) {
    const splitString = float.toFixed(2).split(".");
    return `<b>${addCommas(splitString[0])}</b>.${splitString[1]}`;
  }
  const handlers = {
    value: {
      label: "Value",
      content: (d) =>
        `${currencySymbols.btc + d.btc} / ${currencySymbols.usd + highlight(d.usd)}`,
    },
    hash: { label: "Hash", content: (d) => truncate(d) },
    type: { label: "Type", content: (d) => format(d) },
    level: { label: "Time", content: (d) => new Date(d).toUTCString() },
    address: { label: "Address", content: (d) => truncate(d) },
    transaction: {
      label: "Transaction",
      content: (d) => truncate(chart.getItem(d).d.hash),
    },
  };
  function getContent(props) {
    return Object.keys(props)
      .map((key) => {
        const handler = handlers[key];
        return `<tr><td><strong>${handler.label}</strong></td><td>${handler.content(
          props[key],
        )}</td></tr>`;
      })
      .join("");
  }
  return {
    show: (props) => {
      headerEl.style.display = props ? "none" : "block";
      contentEl.innerHTML = props ? getContent(props) : "";
    },
  };
}

// Converts dates to milliseconds
function toMS(dt) {
  return Date.UTC(
    dt.getFullYear(),
    dt.getMonth(),
    dt.getDate(),
    dt.getHours(),
    dt.getMinutes(),
    dt.getSeconds(),
    dt.getMilliseconds(),
  );
}

// Make the timebar range a bit broader
async function setTimebarRange() {
  const offset = 1000;
  const range = await timebar.range();
  await timebar.range(toMS(range.dt1) - offset, toMS(range.dt2) + offset, {
    animate: false,
  });
}

async function foregroundItemsInRange() {
  await chart.foreground(timebar.inRange);
}

async function closeCombos() {
  await chart.combo().close(comboIds, { animate: false });
}

// Hides some autogenerated arrows on combolinks
function hideArrowsFromComboLinks() {
  const props = [];
  chart.each({ type: "link", items: "toplevel" }, (link) => {
    if (chart.combo().isCombo(link.id2)) {
      props.push({ id: link.id, a1: false, a2: false, c2: "#d3d3d3" });
    }
  });
  chart.setProperties(props);
}

async function revealLinks(item) {
  const itemType = item.d.type;
  if (itemType === "transaction") {
    const linksToReveal = [];
    const neighbours = await graph.neighbours(item.id);
    neighbours.links.forEach((linkId) => {
      const link = chart.getItem(linkId);
      const isChildNode = !!chart.getItem(link.id2).parentId;
      const isOpenCombo = !!chart.combo().isOpen(chart.combo().find(link.id2));
      if (isChildNode && isOpenCombo) linksToReveal.push(linkId);
    });
    chart.combo().reveal(linksToReveal);
  } else if ((itemType === "input" || itemType === "output") && item.parentId) {
    const linksToReveal = await graph.neighbours(item.id).links;
    chart.combo().reveal(linksToReveal);
  }
}

function showInfoAndRevealLinks() {
  currentViewState.itemInfo.show();
  chart.combo().reveal([]);
  const item = chart.getItem(chart.selection()[0]);
  if (item && item.type === "node") {
    currentViewState.itemInfo.show(item.d);
    revealLinks(item);
  }
}

// Zoom to fit all items
async function zoomToFit() {
  await Promise.all([
    chart.zoom("fit", { animate: true, time: 1000 }),
    timebar.zoom("fit", { animate: true, time: 1000 }),
  ]);
  await foregroundItemsInRange();
}

// Zoom to specific items
async function zoomToIds(ids) {
  await Promise.all([
    chart.zoom("fit", { animate: true, time: 1000, ids }),
    timebar.zoom("fit", { animate: true, time: 1000, id: ids }),
  ]);
  await setTimebarRange();
  await foregroundItemsInRange();
}

async function dismissChain() {
  await zoomToFit();
  await chart.filter(() => true, { type: "node" });
  await chart.hide(data.chainLinkIds);
  await chart.animateProperties(data.layout.organic);
  comboIds = await chart.combo().combine(data.comboDefs, { select: false });
  hideArrowsFromComboLinks();
  await zoomToFit();
}

async function inspectChain() {
  await zoomToIds(data.chainNodeIds);
  await chart.combo().uncombine(comboIds || data.comboIds, { select: false });
  await chart.filter((node) => data.chainNodeIds.includes(node.id), {
    type: "node",
  });
  await chart.show(data.chainLinkIds);
  await chart.animateProperties(data.layout.sequential);
  await zoomToFit();
}

async function dismissTxs() {
  await chart.filter(() => true, { type: "link", items: "toplevel" });
  await zoomToFit();
}

async function inspectTxs(ids) {
  const neighbours = await chart.graph().neighbours(ids, { hops: Infinity });
  await chart.filter((link) => neighbours.links.includes(link.id), {
    type: "link",
    items: "toplevel",
  });
  await zoomToIds([...ids, ...neighbours.nodes, ...neighbours.links]);
}

// Introduce a 500ms pause to make zooming transitions easier to follow;
async function pauseAnimation() {
  await new Promise((resolve) => setTimeout(resolve, 500));
}

// Action mapping for forward currentViewState changes
async function getPrevState() {
  await {
    0: async () => {
      await dismissTxs();
    },
    1: async () => {
      await dismissTxs();
      await pauseAnimation();
      await inspectTxs(["t1013", "t886"]);
    },
    2: async () => {
      await dismissChain();
      await pauseAnimation();
      await inspectTxs(["t282", "t283"]);
    },
    3: async () => {
      await inspectChain();
    },
  }[currentViewState.index % 4]();
}

// Action mapping for backwards currentViewState changes
async function getNextState() {
  await {
    0: async () => {
      await dismissChain();
    },
    1: async () => {
      await inspectTxs(["t1013", "t886"]);
    },
    2: async () => {
      await dismissTxs();
      await pauseAnimation();
      await inspectTxs(["t282", "t283"]);
    },
    3: async () => {
      await dismissTxs();
      await pauseAnimation();
      await inspectChain();
    },
  }[currentViewState.index % 4]();
}

function disableUI() {
  button.prev.disabled = true;
  button.next.disabled = true;
}

function enableUI() {
  button.prev.disabled = currentViewState.index === 0;
  button.next.disabled = false;
}

// Update view text and text between buttons
function updateView() {
  Object.keys(views).forEach((i) => {
    views[i].style.display = "none";
  });
  views[currentViewState.index % 4].style.display = "block";
  viewEl.innerHTML = `${(currentViewState.index % 4) + 1} of 4`;
}

function enableUserInteraction() {
  enableUI();
  chart.on("selection-change", showInfoAndRevealLinks);
  // Disable node dragging
  chart.on("drag-start", ({ preventDefault, type }) => {
    if (type === "node") {
      preventDefault();
    }
  });

  timebar.on("change", foregroundItemsInRange);

  // Click handlers
  const handlers = {
    prev: async () => {
      currentViewState.index--;
      updateView();
      await getPrevState();
    },
    next: async () => {
      currentViewState.index++;
      updateView();
      await getNextState();
    },
  };

  ["prev", "next"].forEach((id) => {
    button[id].addEventListener(
      "click",
      async () => {
        // Override change event when zooming and manually foreground items
        timebar.off("change");
        closeCombos();
        disableUI();
        await handlers[id]();
        enableUI();
        timebar.on("change", foregroundItemsInRange);
      },
      false,
    );
  });
}

async function startKeyLines() {
  graph = KeyLines.getGraphEngine();
  graph.load(data);
  currentViewState.itemInfo = getSelectedItemInfo();

  const chartOpts = {
    backColour: "#282828",
    controlTheme: "dark",
    defaultStyles: { comboGlyph: null },
    drag: { links: false },
    handMode: true,
    iconFontFamily: "Font Awesome 5 Free",
    imageAlignment: { "fas fa-exchange-alt": { e: 0.7 } },
    minZoom: 0.001,
    overview: { icon: false, shown: false },
    selectionColour: "#d3d3d3",
  };

  const timebarOpts = {
    area: { colour: "#d24dff" },
    backColour: "#282828",
    controlBarTheme: "dark",
    scale: { highlightColour: "#363636" },
    sliders: "none",
    type: "area",
  };

  [chart, timebar] = await KeyLines.create([
    { container: "klchart", type: "chart", options: chartOpts },
    { container: "kltimebar", type: "timebar", options: timebarOpts },
  ]);

  await chart.load(data);
  await timebar.load(data);
  await zoomToFit();
  hideArrowsFromComboLinks();
  enableUserInteraction();
}

function loadWebFonts() {
  document.fonts.load('24px "Font Awesome 5 Free"').then(startKeyLines);
}

window.addEventListener("DOMContentLoaded", loadWebFonts);
export const data = {
  type: "LinkChart",
  chainLinkIds: [
    "c172",
    "c174",
    "c171",
    "c175",
    "c157",
    "c176",
    "c156",
    "c177",
    "c155",
    "c178",
    "c124",
    "c179",
    "c123",
    "c180",
    "c122",
    "c181",
    "c182",
    "c183",
    "c184",
    "c185",
    "c186",
    "c210",
    "c211",
    "c212",
  ],
  chainNodeIds: [
    "t1162",
    "i2569",
    "o2922",
    "o2923",
    "o2918",
    "i2570",
    "t1159",
    "t1163",
    "i2566",
    "o2917",
    "o2924",
    "o2925",
    "o2916",
    "i2571",
    "t1158",
    "t1164",
    "i2565",
    "o2915",
    "o2926",
    "o2927",
    "o2743",
    "i2572",
    "t1075",
    "t1165",
    "i2409",
    "o2742",
    "o2928",
    "o2929",
    "o2741",
    "i2573",
    "t1074",
    "t1166",
    "i2408",
    "o2740",
    "o2930",
    "o2931",
    "o2739",
    "i2574",
    "t1073",
    "t1167",
    "i2407",
    "o2738",
    "o2932",
    "o2933",
    "o2466",
    "i2575",
    "t975",
    "t1168",
    "i2168",
    "o2465",
    "o2934",
    "o2935",
    "o2464",
    "i2576",
    "t974",
    "t1169",
    "i2167",
    "o2463",
    "o2936",
    "o2937",
    "o2462",
    "i2577",
    "t973",
    "t1170",
    "i2166",
    "o2461",
    "o2938",
    "o2939",
    "i2578",
    "t1171",
    "o2940",
    "o2941",
    "i2579",
    "t1172",
    "o2942",
    "o2943",
    "i2580",
    "t1173",
    "o2944",
    "o2945",
    "o2946",
    "i2581",
    "t1174",
    "o2947",
    "o2948",
    "i2763",
    "t1304",
    "o3213",
    "o3214",
    "i2764",
    "t1305",
    "o3215",
    "o3216",
    "i2765",
    "t1306",
    "o3217",
    "o3218",
    "i2766",
    "t1307",
    "o3219",
    "o3220",
  ],
  comboIds: [
    "p297",
    "p299",
    "p300",
    "p296",
    "p301",
    "p272",
    "p302",
    "p271",
    "p303",
    "p270",
    "p304",
    "p249",
    "p305",
    "p248",
    "p306",
    "p307",
    "p247",
    "p308",
    "p309",
    "p310",
    "p311",
    "p312",
    "p313",
    "p345",
    "p346",
    "p347",
  ],
  comboDefs: [
    {
      ids: ["o2462", "i2167"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3Q16JiLL6g6mMQUHGphzHs3Xs91NLf97Z8",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.11920904, 0.11920904],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2464", "i2168"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3MXJ4B9NFJacvuNy2mrzDUZWQairz6xvTn",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.11904637, 0.11904637],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2466", "i2407"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3DnCSFF56ddHp1K4nutDtqjzRqBNAg51rd",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.11807599, 0.11807599],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2739", "i2408"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3AGByVZLSns5Mg3G25nNhsXqXYSuScP2Cr",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.11736389, 0.11736389],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2741", "i2409"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3B3jbAfFccp3jqPm3kSHrPrY818bCNJMU2",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.11403361, 0.11403361],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2743", "i2565"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3Dan6U5PCSHmYk43ixwjZDxBYcTEEBYDT8",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.11248838, 0.11248838],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2916", "i2566"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "35ArfsDSVPrCjrRYmyVrYhjfaX8JuWThHC",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.11057369, 0.11057369],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2918", "i2569"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3Ed6Ss1Fb2M72APjYKdvPhkNRnDrEWhDC7",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.1093351, 0.1093351],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2922", "o3213"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3HzNzgAEDJJhAxLsABhMzuWUe2BGMKVkEM",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.0013701400000000002, 0],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 0,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 2,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2923", "i2570"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3EYJuira3E3rroyh1nsVWq7fgQaiPLtXk6",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.10871084, 0.10871084],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2925", "i2571"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3J68AUYk13BbYZq1pLtwwYRsyDwWfLmzud",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.1081993, 0.1081993],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2927", "i2572"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3Qa9VMVddmmAAajYwqLBj8LbtuvX2qtVRp",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.10784356, 0.10784356],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2929", "i2573"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "37iFM4M318yoG4jnBJJUWKbCBdTd3bPcuR",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.10710104, 0.10710104],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2931", "i2574"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3G4f7YbMYwt3QKqYqKUZHdYzZSws3G6oZw",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.10690306, 0.10690306],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2933", "i2575"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3NqAe2s6yDVSsYfugp8uTawdDcQYKEEUcP",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.10676472, 0.10676472],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2934", "o2936", "o3215", "o3217", "o3219"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "18jLvnG43HSe5kahL8veG3h4ts28LrNqg4",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.0023462400000000003, 0],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 0,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 5,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2935", "i2576"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "35b6tm2JP43pvEtpziXTdTtKyXXbW2QXUs",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.10616046, 0.10616046],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2937", "i2577"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3HfhnXTmuJ9Q6pZrx2bajepotsFS1GaXLz",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.10597464, 0.10597464],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2939", "i2578"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3P5VJvfUs4m8sveX5W5LA4F9ZEUT7U9Mp2",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.09384145, 0.09384145],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2941", "i2579"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3GFrjhxYVT3ddBhhQ1WPAohLaSFcVTBrrY",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.09196385, 0.09196385],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },
        e: 3,
        g: [
          {
            p: 270,
            t: 1,
            c: "#04b5e5",
            b: "#04b5e5",
            fc: "#282828",
            r: 12,
          },
          {
            p: 90,
            t: 1,
            c: "#f2a900",
            b: "#f2a900",
            fc: "#282828",
            r: 12,
          },
        ],
      },
    },
    {
      ids: ["o2943", "i2580"],
      open: false,
      style: {
        d: {
          type: "address",
          address: "3PVR9yiKvopd3xtxP2d7ByQpMXgYhGRhPP",
        },
        c: "#282828",
        bw: 0,
        donut: {
          v: [0.08615072, 0.08615072],
          c: ["#f2a900", "#04b5e5"],
          bw: 0,
        },
        oc: {
          c: "#282828",
          b: "#d3d3d3",
          bw: 10,
        },

// ...truncated 367605 lines
<!doctype html>
<html lang="en" style="background-color: #2d383f">
  <head>
    <meta charset="utf-8" />
    <title>Bitcoin Transactions</title>
    <link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/keylines.css" />
    <link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/minimalsdk.css" />
    <link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/sdk-layout.css" />
    <link rel="stylesheet" type="text/css" href="@ci/theme/kl/css/demo.css" />
    <link
      rel="stylesheet"
      type="text/css"
      href="@fortawesome/fontawesome-free@5.15.4/css/fontawesome.css"
    />
    <link
      rel="stylesheet"
      type="text/css"
      href="@fortawesome/fontawesome-free@5.15.4/css/solid.css"
    />
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body>
    <div id="klchart" class="klchart klchart-timebar"></div>
    <div id="kltimebar" class="kltimebar"></div>
    <script type="module" src="./code.js"></script>
  </body>
</html>
.klchart {
  border: none;
  background-color: #282828;
}
.kltimebar {
  border: none;
  border-top: 1px dashed #333;
  background-color: #282828;
}
td {
  text-align: left;
  padding: 5px;
}
#view {
  width: 40px;
}
.view {
  min-height: 220px;
}
.buttons {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 60px;
}
.svg-grid > svg {
  width: 100%;
  height: 40px;
}
.svg-grid {
  margin: 20px;
  display: grid;
  grid-gap: 5px;
  grid-template: 1fr 1fr/ 1fr 1fr;
}
.c1 {
  grid-row: 1/2;
  grid-column: 1/2;
}
.c2 {
  grid-row: 1/2;
  grid-column: 2/-1;
}
.c3 {
  position: relative;
  grid-row: 2/-1;
  grid-column: 1/2;
}
.c4 {
  grid-row: 2/-1;
  grid-column: 2/-1;
}

Terms of use

These terms do not alter or supersede any existing agreements between you (or your employer) and us.

By accessing or using any Content you agree to be bound by these Terms of Use. Please review these terms carefully before using the website.

The contents of this website, including but not limited to any text, code samples, API references, schemas, interactive tools, and other materials (collectively, the 'Content'), are made available for informational and internal evaluation purposes only. All intellectual property rights in the Content are reserved. No licence is granted to use the Content for any commercial purpose, or to copy, distribute, modify, reverse-engineer, or incorporate any part of the Content into any product or service, without our prior written consent.

This Content is provided “as is” and “as available,” without any representations, warranties, or guarantees of any kind, whether express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, non-infringement, or accuracy. To the fullest extent permitted by applicable law, we expressly exclude and disclaim all implied warranties, conditions, and other terms that might otherwise be implied.

We disclaim all liability for any loss or damage, whether direct, indirect, incidental, consequential, or otherwise, arising from any reliance placed on the Content or from your use of it, to the fullest extent permitted by applicable law. By continuing to access or use the Content, you acknowledge and agree to these terms.