Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

The Trade Nobody Puts in the Wallet Infrastructure Pitch Deck

1 September 2026 at 11:51

A finance team I keep hearing about runs month-end close on a spreadsheet that used to be one tab. Now it’s forty. Not because the business grew forty times — someone kept saying yes to new assets, and every asset meant a new wallet, a new balance to fetch, and another key to manage.

Nobody designed it that way on purpose. Wallet-per-asset is the architecture you fall into when the first integration works and the second looks almost identical. It’s only around asset thirty that finance starts asking why reconciliation takes four days instead of four hours.

What Forty Wallets Actually Cost

The visible cost is obvious: more infrastructure, more keys, more places to fail. The cost nobody budgets for shows up somewhere else — in finance, support, and operations.

A user asks where another balance went because it sits behind a different wallet. Finance runs forty reconciliation processes where one could have done the job, and each can fail differently. A fix to one flow doesn’t necessarily improve the other thirty-nine. At a small scale, that’s annoying. At forty assets, it becomes a second job.

The One-Wallet Fix and What It Actually Changes

Collapsing that architecture into one balanced view sounds like a UI decision. It isn’t. Underneath the interface, it’s an infrastructure and custody decision.

Instead of treating every asset as its own operational lane, the product gives users and finance one place to see balances and one process to reconcile them. The report becomes simpler because the architecture underneath it becomes simpler first.

The second-order effects are more interesting. Support gets fewer questions about missing balances. New-asset launches can move faster because the team no longer has to recreate the same custody setup every time. Finance gets one reporting process instead of dozens — and eventually starts trusting the numbers again.

The Part That Doesn’t Disappear

Consolidating custody doesn’t remove risk; it relocates it. Forty small operational risks become one larger relationship that has to be governed properly, which is often a cleaner model but still comes with its own responsibilities.

Someone still has to own provider oversight, permissions, security policies, access controls, and the consequences if the underlying infrastructure fails. The difference is that the risk is now concentrated enough to be visible, documented, and managed instead of being scattered across dozens of separate wallet setups.

Three Answers to Who Actually Holds the Key

Once a team decides that one wallet is better than forty, the next question is harder: where should that unified infrastructure actually live? The three models below solve the same operational problem differently, mainly in how much infrastructure and control the business chooses to hand off.

1 | Coinbase | Managed Wallet Infrastructure

Coinbase CDP Wallets take the managed-platform route. The stack includes TEE-backed key infrastructure, KYT screening, and APIs covering embedded and server wallets.

For a product team, the attraction is consolidation: wallet creation, security infrastructure, and compliance tooling sit behind one development layer rather than being assembled asset by asset.

The trade-off is equally clear. More infrastructure is delegated to an established provider, so the team has less of the underlying wallet stack to build and operate itself. Governance therefore shifts toward managing the provider relationship, permissions, policies, and integration rather than managing every key system independently.

2 | WhiteBIT | Unified Multi-Asset Custody

WhiteBIT’s Wallet-as-a-Service approaches the same problem from a multi-asset custody angle. It supports 340+ assets across 80+ networks within a single wallet, with address generation and AML checks built into the infrastructure.

For businesses managing many assets, the practical gain is fewer parallel systems. The same environment can support multiple networks and assets instead of requiring a new custody workflow every time the product expands its asset list.

Here too, simplification comes with concentration. Custody and a larger part of the operational layer sit with one provider, which reduces internal complexity but makes provider governance, security standards, access controls, and operational resilience more important.

3 | Openfort | More Control Over the Key Layer

Openfort takes a different route. Its Wallet-as-a-Service stack is built around non-custodial infrastructure, with self-hostable key management through OpenSigner and a policy layer for controlling how wallets operate.

The practical difference is configurability. Teams can define transaction rules, session permissions, contract allowlists, spending limits, and gas sponsorship without rebuilding the wallet stack around each use case. That makes Openfort especially relevant for products that need wallet behavior to vary across users, applications, or workflows.

That flexibility also keeps more operational responsibility with the product team. Key policies, security rules, and wallet behavior need to be actively governed, which can suit teams that want a more programmable infrastructure layer rather than simply outsourcing most of the wallet logic to a provider.

The Design Principle Underneath the Reconciliation Win

The clean balance view is real, and finance may feel the benefit first. But the honest way to judge wallet infrastructure isn’t by how clean the demo looks. It’s by what happens three years later, after asset coverage, transaction volume, and headcount have all moved in directions nobody predicted.

A system that turns forty reconciliation problems into one can remove a surprising amount of operational noise, but that simplification only works if the remaining relationship is governed properly. Forty risks becoming one is valuable only when somebody is clearly responsible for the one.

That responsibility isn’t a footnote to the architecture decision. It sits at the center of it, because the goal was never simply to make the balance screen cleaner — it was to make the underlying system easier to understand, operate, and trust.

Disclaimer: This is not financial or investment advice. Do your own research before making any decisions. Use at your own risk.


The Trade Nobody Puts in the Wallet Infrastructure Pitch Deck was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.

The Most Dangerous Person in the World Might Be a Clerk

21 August 2026 at 10:22

That power is finally changing hands, and not where anyone is looking.

Somewhere tonight, a family will lose a house theyve lived in for thirty years. Not to a fire. Not to a flood. To a line in a book.

Someone with access to the right record will change one entry, a name, a plot number, and land that belonged to three generations now belongs to a stranger. No broken window. No theft you can point to. Just ink.

This isn’t rare. In Honduras, officials once quietly rewrote the government’s land database and handed themselves beachfront property. Across huge stretches of the world, families farm the same soil their whole lives and still cant prove a single inch of it is theirs. One clerk, one bribe, one “sorry, your file was lost,” and the ground under a life is gone.

Heres the part that should stop you cold. The same is true of almost everything you think you own.

Everything you own is a line in someone’s book

Your house isn’t yours because you live in it. Its yours because a record somewhere says so. Your money isnt really in your pocket, its a number in your bank’s book, and the bank promises the number is real. Even your name, your birthday, the plain fact that you legally exist, its all an entry in some official register.

Strip life down to the wiring and you keep hitting the same thing underneath all of it. A ledger. A list. Who owns what. Who owes what. Who is who.

Civilization doesnt actually run on money, or gold, or armies. It runs on ledgers. And heres the truth weve lived with so long we stopped seeing it.

Someone has always kept the book. And whoever keeps the book holds the power.

We have only ever swapped scribes

Go back five thousand years. The oldest human writing anyone has ever dug up isnt poetry or prayer. Its accounting. Clay tablets from the first cities, scratched with who owed how much grain. Before we wrote down a single story about ourselves, we wrote down the ledger.

And from that day, whoever held it ruled. The temple scribe decided what you owed the gods. The king’s men decided what you owed the crown. If the scribe made a mark against your name, you were in debt, and there was no arguing with the book.

Not much has really changed. Weve just kept swapping scribes.

Today the book is kept by banks, and land offices, and government databases. Nicer buildings. Same deal. You are rich because a bank’s computer says so. You own your home because a registry’s file says so. You exist because a database says so. Every time, youre trusting a keeper, some stranger, some system, to hold the truth about your life and not lose it, not sell it, not change it.

Most of the time, they dont. But youve seen what happens when they do. A currency printed until your savings turn to wallpaper. A land record that “disappears.” An account frozen by someone who never has to explain themselves to you. Every one of those is the same ancient wound. The keeper had power over you, and you had none over the keeper.

The quiet earthquake nobody explained to you

Now. For the first time in five thousand years, that is changing. And almost nobody is telling the story straight, because they keep burying it under words designed to make your eyes glaze. Crypto. Tokens. Coins. Moon. Forget all of it.

Heres the whole idea, in a picture a child could follow.

Imagine a village where everyone owns a bit of land. Instead of one big book locked in the chief’s hut, every single family keeps their own identical copy of the record. Someone sells a field, and everyone updates their copy at the same moment. Now picture one man sneaking home to rewrite his copy so it says he owns his neighbor’s land too. He marches to the market waving it. And every other family opens their copy, a hundred books that all say hes lying. His fake doesnt stand a chance.

Thats it. Thats a blockchain. Not a coin. A book that everyone holds a copy of, so no single person can quietly change it, because to rewrite the truth you’d have to rewrite everyone’s copy at once, and you cant.

I keep circling this idea in this newsletter, that blockchain is best understood as plumbing and rails, not a casino (The New Rails is the long version). But heres the plainest way I can put it. For the first time, we have a record with no keeper. A ledger that sits in no one’s drawer. No one to bribe, because theres no single clerk. No one to trust, because you dont have to. You can just check it yourself.

Read that twice. The oldest lever of power on earth, keeping the book, just stopped needing a keeper.

So where does a change this big show up first?

Not where youd expect. And this is the part almost everyone gets wrong.

Everyone stares at the top. Will there be one world currency, whats the Fed doing, is the dollar finished. And everyone stares at the bottom. Is my coin up, is it down, should I buy. Up there, and down here. Thats where all the noise lives, and all the fireworks.

But your ledgers, the ones that actually run your daily life, arent up there or down here. Theyre not at the world bank and theyre not in a coin on your phone. The deed to your home, the record of your birth, the title to your land, those sit in a filing cabinet, in a building, in your city.

The city is where the book has always physically lived. Which makes the city the one place the keeper’s grip is quietly being pried loose, right now, one unglamorous upgrade at a time. Not by revolution. By clerks quietly changing which kind of book they use.

Let me show you it happening, in real places, to real people. Because once you see it, you cant unsee it.

Your name

Start with who you are.

In Buenos Aires, more than three and a half million people now carry their own identity, their birth record, their proof they exist, in a wallet on their phone. Not a copy the city lets them peek at. The real thing, in their hands, that they control.

And the city built it so cleverly it barely made the news. Normally, to prove youre old enough, or married, or a citizen, you hand over everything, your whole ID, all your data, to whoever asks. Buenos Aires uses a quiet trick that lets you prove just the one fact that matters, yes, over eighteen; yes, a resident, without handing over the rest. Picture a bouncer who can confirm youre old enough without ever learning your name or your address. You prove it. He learns nothing else. The keeper who used to hold your whole identity, and could lose it or leak it, is simply cut out of the middle.

Your home

Remember that family, losing a house to a line of ink? This is the fix.

The country of Georgia, the one by the Black Sea, moved its land titles into a keeper-less record and cut the time to sell a property from days to minutes, and made “sorry, your file was lost” close to impossible. India is doing it at a scale thats hard to even picture. By late 2025, hundreds of millions of government records were anchored into a book no clerk can quietly rewrite. City after city, the same move, taking the ledger out of the drawer.

And once a record gets that solid, something wild becomes possible. In Dubai, ownership got so trustworthy that you can now slice a single apartment into thousands of tiny shares and trade them like nothing. One flat, split into pieces, and a slice of it sold out in under two minutes, to strangers on the far side of the planet who never met, never signed a paper, never had to trust a keeper. They just trusted the book that no one can fake. (That slicing-up of the world’s assets has a name and a staggering scale, I mapped it in Tokenization: The 16 Trillion Dollar Shift.)

Your money

A tiny Swiss town called Zug, smaller than a lot of city neighborhoods, let people start paying taxes in digital money years ago, and told businesses plainly, in writing, how the new records would be treated. It didnt promise no rules. It promised a book you could rely on.

And that alone pulled in builders from all over the world. Because the thing everyone is really starving for isnt hype, and it isnt some coin going up. Its a record they can finally trust without trusting a person. (One entire country, Estonia, put nearly its whole government onto this kind of backbone, I broke that down here. A city is that same move, shrunk to a size that can happen almost anywhere on earth.)

Now the part the sales-people leave out

You deserve the whole truth, not a pitch. So here it is.

Taking the book away from the old keeper is not the same as setting you free. Sometimes the old keeper just gets swapped for a new one, with a friendlier logo, and your money in his pocket.

A few years back, the mayor of Miami launched a city coin and dangled a dream. Buy in, and maybe one day the city gets so rich off it that it stops taxing you. People bought. It soared. Then it fell more than ninety-nine percent and quietly died. It never recorded anything. It never proved anything. It never protected a single home or name. It did exactly one thing, go up, then down, and take real money from real people on the way. That wasnt a book with no keeper. That was a new keeper, in a hoodie, running the oldest trick there is.

Theres a grander version too. Off the coast of Honduras, investors built a private city that runs less like a town and more like an app you live inside. Its own rules, its own courts, pay in Bitcoin, register a company in an hour. Same technology as Buenos Aires. Opposite spirit entirely. One hands the book to the people. The other hands it to a company. The country called the whole thing unconstitutional; the project sued for a sum near a third of the nation’s yearly income. Watch closely and you learn the real lesson. Sometimes “innovation” isnt taking the keeper away at all. Its just becoming the keeper.

The one question to keep for life

So heres the single thing to carry out of all this. The question that will keep you clear for decades, long after youve forgotten every name in this piece.

Whenever anyone, a city, a company, a founder, a government, tells you theyre putting something “on the blockchain,” dont ask whether its exciting. Ask one thing.

Did the keeper actually disappear, or did the keeper just change costume?

Three quick ways to tell. Can you check it yourself, without asking anyone’s permission? A book with no keeper is open to all. A new keeper keeps the key. Does it still protect you if the price of everything crashes to zero? A real record, your home, your name, doesnt care about any price. A new keeper’s coin lives and dies on it. And if it all falls apart, who gets hurt, you, or them? If youre the one who can lose everything while someone else collects, youve just met the new keeper.

No keeper, and youre freer than any generation before you. New keeper, and its the same old chain with a shinier link. That one question cuts through all of it.

Where this is all going

Zoom out, and heres the destination.

Every city that takes its book out of the drawer is doing it in roughly the same way, to the same standards, on records built to talk to each other. Which means, slowly and quietly, the books are starting to connect. Picture a world where your name, your home, your money live in records that no single power, no clerk, no bank, no government, anywhere, can secretly change or seize.

Thats the real thing this newsletter keeps pointing at. Not one currency for the planet, handed down from on high by treaty. Something deeper than that. One earth where proving what is yours finally doesnt depend on trusting whoever happens to be holding the pen. The rails for it are being laid right now, and not from the top, and not from the bottom, but from the middle. From your city.

So stop watching the coin prices. They are the fireworks, not the fire.

Watch your city instead. The morning it moves your deeds, your ID, your records onto a book that no one can quietly rewrite, that is the morning a leash you never knew was around your neck goes slack. It wont make the news. It never does. But it will change, forever, the answer to the oldest question a human being can ask.

When I say this is mine, and this is who I am, who do I have to trust to make it true?

For five thousand years, the answer was: someone else.

For the first time, the answer can be: no one. Just the book. And a copy of it, at last, in your own hands.

If you want to understand where finance is heading before it becomes obvious, Naked Market is where these dots get connected every week.
Subscribe free →

Start here — the pinned welcome post

One Planet, 180 Currencies. Something’s Got To Give.

Keep reading, in this thread

-More soon


The Most Dangerous Person in the World Might Be a Clerk was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.

EIP-712 Explained: Sign and Verify Typed Data with ethers.js and Solidity

17 August 2026 at 12:43

Imagine your application wants a user to authorize an off-chain action:

Transfer 100 USDC
to 0x...
nonce 42
deadline ...

You could serialize that data into a string and ask the wallet to sign it. But then subtle questions appear: Which serialization is canonical? Is 100 a string or an integer? Which contract is allowed to consume the signature? Can the same signature work on another chain?

EIP-712 solves the encoding side of this problem by defining a deterministic way to hash and sign typed structured data. Instead of signing arbitrary JSON text, the wallet signs a digest derived from explicit Solidity-like types, the message, and an application-specific domain.

That makes EIP-712 particularly useful for permits, meta-transactions, order protocols, delegated actions, and other off-chain authorizations that are later verified on-chain.

Why signing plain strings is not enough

Ethereum wallets can sign arbitrary messages using mechanisms such as personal_sign. This works well when the thing being signed really is a human-readable message.

Structured application data is different.

Suppose two applications serialize this object differently:

{"to":"0x...","amount":"100"}

and:

{
"amount": "100",
"to": "0x..."
}

They may represent the same intent to a developer, but they are different byte strings.

Plain message signing also does not inherently describe Solidity types. A wallet sees bytes or text rather than an explicit structure such as address to, uint256 amount, and uint256 nonce.

EIP-712 defines a typed encoding and hashing scheme instead. Wallets can use that structure to present meaningful fields to the user rather than an opaque serialized blob.

EIP-712 Explained: Domain, Types, and Message

Consider a transfer authorization:

const domain = {
name: "ExampleApp",
version: "1",
chainId: 1,
verifyingContract: "0x1234567890123456789012345678901234567890",
};
const types = {
Transfer: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
],
};
const value = {
to,
amount,
nonce,
deadline,
};

There are four important pieces.

Domain identifies the application context in which the signature is valid.

Types define the exact structure and Solidity-compatible types being signed.

Primary type is the root structure — Transfer in this example.

Message is the actual set of values.

The domain is what gives EIP-712 its domain separation. Two applications can sign structurally identical Transfer messages without necessarily producing interchangeable signatures.

For production authorizations, two domain fields are especially important:

chainId
verifyingContract

chainId binds the signature to a network, while verifyingContract binds it to a particular contract address. Both become part of the EIP-712 domain separator and therefore affect the final digest.

Without appropriate domain separation, a signature intended for one context may be meaningful in another.

How the EIP-712 Hash Is Built

EIP-712 does not sign your JavaScript object or its JSON serialization.

Conceptually, the final digest is:

keccak256(
0x1901 ||
domainSeparator ||
hashStruct(message)
)

The 0x1901 prefix comes from the signed-data encoding scheme used by EIP-712.

For our Transfer structure, its encoded type is effectively:

Transfer(address to,uint256 amount,uint256 nonce,uint256 deadline)

Hashing this definition produces the typeHash:

keccak256(
"Transfer(address to,uint256 amount,uint256 nonce,uint256 deadline)"
)

The message’s structHash is then calculated from the type hash and encoded field values.

Conceptually:

keccak256(
abi.encode(
TRANSFER_TYPEHASH,
to,
amount,
nonce,
deadline
)
)

The domain is hashed using the same EIP-712 struct-hashing rules to produce the domain separator. Finally, the message struct hash and domain separator are combined into one digest.

This digest — not JSON.stringify(value) — is what ultimately gets signed.

That distinction is the reason JavaScript and Solidity can independently reconstruct exactly the same value.

At this point, the full EIP-712 flow looks like this:

Signing EIP-712 Typed Data in JavaScript

With ethers v6, the high-level API is signer.signTypedData(domain, types, value). ethers handles the EIP-712 encoding and hashing internally.

A browser example can stay compact:

import { BrowserProvider } from "ethers";

const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const chainId = (await provider.getNetwork()).chainId;
const domain = {
name: "ExampleApp",
version: "1",
chainId,
verifyingContract: "0x1234567890123456789012345678901234567890",
};
const types = {
Transfer: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
],
};
const value = {
to: "0x0000000000000000000000000000000000000000",
amount: 100_000_000n, // 100 USDC with 6 decimals
nonce: 42n,
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
};
const signature = await signer.signTypedData(
domain,
types,
value
);

Notice that the frontend does not manually hash individual fields. That is intentional.

Unless you are implementing infrastructure specifically around EIP-712 encoding, use the library implementation instead of recreating the algorithm yourself.

The important part is that the frontend schema must exactly match the Solidity schema.

Verifying an EIP-712 Signature in Solidity

On-chain, OpenZeppelin’s EIP712 contract reconstructs the domain-aware digest, while ECDSA performs signer recovery. OpenZeppelin explicitly documents the _hashTypedDataV4(structHash) plus ECDSA.recover pattern.

Here is the Solidity side of the same example:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {EIP712} from
"@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {ECDSA} from
"@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
contract TransferAuthorizer is EIP712 {
struct Transfer {
address to;
uint256 amount;
uint256 nonce;
uint256 deadline;
}
bytes32 private constant TRANSFER_TYPEHASH =
keccak256(
"Transfer(address to,uint256 amount,uint256 nonce,uint256 deadline)"
);
mapping(address => mapping(uint256 => bool))
public usedNonces;
constructor() EIP712("ExampleApp", "1") {}
function authorizeTransfer(
address expectedSigner,
Transfer calldata transfer,
bytes calldata signature
) external {
require(
block.timestamp <= transfer.deadline,
"Authorization expired"
);
require(
!usedNonces[expectedSigner][transfer.nonce],
"Nonce already used"
);
bytes32 structHash = keccak256(
abi.encode(
TRANSFER_TYPEHASH,
transfer.to,
transfer.amount,
transfer.nonce,
transfer.deadline
)
);
bytes32 digest = _hashTypedDataV4(structHash);
address recoveredSigner =
ECDSA.recover(digest, signature);
require(
recoveredSigner == expectedSigner,
"Invalid signature"
);
usedNonces[expectedSigner][transfer.nonce] = true;
// Execute the authorized business operation here.
}
}

_hashTypedDataV4 combines the message struct hash with the contract's EIP-712 domain separator and produces the final digest expected by the signature verification logic.

Using OpenZeppelin is preferable to manually maintaining EIP-712 domain and ECDSA recovery code. Apart from reducing code, it avoids subtle mistakes around domain construction and signature handling.

One additional production nuance: ECDSA.recover verifies signatures from EOAs. If your application must support smart contract wallets, account abstraction, or multisigs, you should also account for ERC-1271-style contract signatures rather than assuming every signer has an ECDSA private key.

EIP-712 Does Not Prevent Replays for You

EIP-712 gives you deterministic structured signing and domain separation. It does not automatically make an authorization single-use.

Consider this perfectly valid signature:

Alice authorizes transfer X

If the contract accepts it today and nothing in contract state marks it as consumed, an attacker may simply submit the same authorization again.

That is why production messages commonly contain a nonce:

uint256 nonce;

and the contract consumes it:

mapping(address => mapping(uint256 => bool))
public usedNonces;

A deadline prevents an authorization from remaining usable indefinitely.

Meanwhile, chainId and verifyingContract provide domain-level protection against signatures being reused in different EIP-712 domains.

These controls solve related but different problems:

nonce              -> prevents repeated execution
deadline -> limits validity in time
chainId -> binds the domain to a chain
verifyingContract -> binds the domain to a contract

The core rule is simple:

A valid signature is not necessarily a valid authorization forever.

Signature verification proves who signed a digest. Your contract still decides whether that authorization is currently acceptable.

Common EIP-712 Mistakes in Production

Most EIP-712 bugs are not cryptography bugs. They are schema or authorization bugs.

1. Different field order between frontend and Solidity.
Transfer(address to,uint256 amount,...) must match exactly on both sides.

2. Type mismatches.
uint256, address, bytes32, and string are not interchangeable representations.

3. Different domain name or version.
ExampleApp version 1 and ExampleApp version 2 intentionally produce different domains.

4. Missing nonce.
A correctly signed authorization may be replayable if contract state does not consume something unique.

5. Missing deadline.
Without expiration, an unused signature may remain actionable much longer than intended.

6. Using abi.encodePacked for the struct hash.
The standard EIP-712 struct encoding corresponds to the ABI-encoded values; OpenZeppelin's documented pattern uses abi.encode.

7. Incorrect domain assumptions around deployments or proxies.
Your frontend must sign against the same effective EIP-712 domain the verification contract reconstructs. Contract addresses, chain changes, and domain-version changes should be treated as protocol changes, not frontend details.

Conclusion

EIP-712 turns Ethereum signatures from loosely defined byte-string signing into deterministic, typed, domain-separated authorization.

The flow is straightforward once the layers are separated:

JavaScript object

typed EIP-712 structure

domain separator + struct hash

EIP-712 digest

wallet signature

Solidity rebuilds digest

recover signer

apply nonce/deadline/business rules

The standard handles how structured data becomes a signable digest. Your application still owns what that signature authorizes, when it expires, and whether it has already been used.

That separation is the key to implementing EIP-712 correctly in production.


EIP-712 Explained: Sign and Verify Typed Data with ethers.js and Solidity was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.

❌
❌