<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rafael Abuawad</title>
    <description>The latest articles on DEV Community by Rafael Abuawad (@rabuawad).</description>
    <link>https://dev.to/rabuawad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F232437%2F0a8251cd-1b32-4675-8f6e-dc4fc2a23885.png</url>
      <title>DEV Community: Rafael Abuawad</title>
      <link>https://dev.to/rabuawad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rabuawad"/>
    <language>en</language>
    <item>
      <title>The House Always Wins: How pump.fun Turned Crypto Into a Fee Machine</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Mon, 26 Oct 2026 01:53:11 +0000</pubDate>
      <link>https://dev.to/rabuawad/the-house-always-wins-how-pumpfun-turned-crypto-into-a-fee-machine-20g5</link>
      <guid>https://dev.to/rabuawad/the-house-always-wins-how-pumpfun-turned-crypto-into-a-fee-machine-20g5</guid>
      <description>&lt;p&gt;Between January 2024 and June 2026, pump.fun produced more than 18.6 million tokens that traded at least once. Nearly seven in ten of them made their last trade on the same day they were born. Eight in ten were gone within 48 hours. Fewer than one in twenty were still trading three months later (&lt;a href="https://cryptopotato.com/nearly-70-of-pump-fun-tokens-die-on-launch-day-coingecko/" rel="noopener noreferrer"&gt;CoinGecko, via CryptoPotato&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The odds of "making it" are worse. A study of 832,941 launches between May and June 2026 found a graduation rate of 0.198%: about two tokens in every thousand reached the point where they leave Pump.fun's bonding curve for an open market (&lt;a href="https://ideas.repec.org/p/arx/papers/2607.02823.html" rel="noopener noreferrer"&gt;Kamat, arXiv 2607.02823&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Over the same period, the platform collected more than $1.2 billion in revenue (&lt;a href="https://defillama.com/protocol/pump?fees=false" rel="noopener noreferrer"&gt;DefiLlama&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Those three facts are the whole story. Almost every token dies. Most traders lose. The house gets paid either way. I build smart contracts for a living, and I've come to believe pump.fun is the single most damaging product this industry has shipped. And if things don't change, it's time to walk away from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the machine works
&lt;/h2&gt;

&lt;p&gt;On pump.fun, anyone can create a token in seconds by filling in a short form. There is no team to vet, no code to audit, and no liquidity to provide. Each new token starts on a bonding curve: an automated price formula where every buy pushes the price up, and every sell pushes it down.&lt;/p&gt;

&lt;p&gt;If enough money flows in, the token "graduates" at roughly $80,000 to $100,000 in market cap and moves to a regular trading pool. Almost none get there. The rest simply stop trading, usually within hours.&lt;/p&gt;

&lt;p&gt;The key detail is where the money goes. pump.fun charges fees on trades along the curve and on its own exchange, PumpSwap. It does not need any token to succeed. It needs tokens to be launched and traded, as many as possible, as fast as possible. As one analysis of CoinGecko's data put it, the platform is paid whether a token lasts six minutes or six months (&lt;a href="https://cryptobriefing.com/pump-fun-token-survival-rate-study/" rel="noopener noreferrer"&gt;Crypto Briefing&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;That is not a flaw in the design. It is the design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who wins
&lt;/h2&gt;

&lt;p&gt;The platform does, spectacularly. pump.fun has generated about $1.9 billion in fees and $1.2 billion in revenue since launch (&lt;a href="https://defillama.com/protocol/pump?fees=false" rel="noopener noreferrer"&gt;DefiLlama&lt;/a&gt;). Its best month, January 2025, brought in $137 million (&lt;a href="https://unchainedcrypto.com/pump-fun-cashed-out-436m-since-mid-october-lookonchain/" rel="noopener noreferrer"&gt;Unchained&lt;/a&gt;). In a 2026 job listing for a Chief Legal Officer, offering up to $5 million a year, the company itself said it made over $500 million in profit the previous year with fewer than 100 people (&lt;a href="https://www.mitrade.com/th/insights/news/live-news/article-3-1840948-20260625" rel="noopener noreferrer"&gt;Mitrade&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Much of that money has left the chain. Onchain trackers estimate the platform has sold about 4.47 million SOL, roughly $780 million, mostly through Kraken (&lt;a href="https://pluang.com/en/news-feed/pumpfun-lanjutan-penjualan-massal-solana-100ribu-sol-dijual-rp780miliar" rel="noopener noreferrer"&gt;Pluang&lt;/a&gt;). In late 2025, wallets linked to pump.fun also moved 436.5 million USDC to Kraken; co-founder Noah Tweedale called reports of a cash-out misinformation and said it was treasury management (&lt;a href="https://forklog.com/en/pump-fun-co-founder-denies-436m-cash-out-to-kraken/" rel="noopener noreferrer"&gt;ForkLog&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Then there was the token. In February 2025, co-founder Alon Cohen dismissed reports of a pump.fun token as wrong (&lt;a href="https://thedefiant.io/news/defi/pump-fun-co-founder-denies-wu-blockchain-reports-about-token-launch" rel="noopener noreferrer"&gt;The Defiant&lt;/a&gt;). Five months later, the PUMP sale raised hundreds of millions of dollars and sold out in 12 minutes (&lt;a href="https://cointelegraph.com/news/pump-fun-lawsuit-slot-machine-rico" rel="noopener noreferrer"&gt;Cointelegraph&lt;/a&gt;). Half of the platform's net revenue now goes to buying back and burning PUMP (&lt;a href="https://defillama.com/token/pump" rel="noopener noreferrer"&gt;DefiLlama&lt;/a&gt;). Put plainly: trader losses are recycled into support for the platform's own token.&lt;/p&gt;

&lt;p&gt;The three founders, Noah Tweedale, Alon Cohen and Dylan Kerler, say they built pump.fun out of frustration with rug pulls (&lt;a href="https://en.wikipedia.org/wiki/pump.fun" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;). That origin story sits awkwardly next to a 2025 WIRED investigation. It linked a developer using Kerler's name to eight tokens launched in 2017, two of which collapsed amid rug-pull accusations, earning that developer up to an estimated $75,000. Neither pump.fun nor Kerler responded to WIRED's requests for comment (&lt;a href="https://bitcoinist.com/linked-to-ico-scams-pump-fun-co-founder-accused-of-rug-pulls-in-2017-report/" rel="noopener noreferrer"&gt;Bitcoinist, summarizing WIRED&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Who loses
&lt;/h2&gt;

&lt;p&gt;Everyone else, mostly. In the first half of 2024, Dune data showed 62.5% of pump.fun traders had lost money, while just 311 wallets, under 0.01% of the total, had made more than $1 million (&lt;a href="https://crypto.news/over-60-pump-fun-traders-saw-losses-less-than-0-01-made-over-1m/" rel="noopener noreferrer"&gt;crypto.news&lt;/a&gt;). By June 2025, only 30.1% of active wallets finished the month in profit (&lt;a href="https://www.coingecko.com/research/publications/pump-fun-traders-are-making-a-comeback" rel="noopener noreferrer"&gt;CoinGecko&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The pattern held into 2026. In March, about half of the roughly 1.4 million wallets trading pump.fun tokens lost money, and around 96% either lost or made less than $500 (&lt;a href="https://www.mexc.com/news/992439" rel="noopener noreferrer"&gt;crypto.news, via MEXC&lt;/a&gt;). Over the six months before that, the top 250 token deployers pulled an estimated $79 million out of traders while launching 194,000 tokens between them (&lt;a href="https://www.mexc.com/it-IT/news/978884" rel="noopener noreferrer"&gt;Protos, via MEXC&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Those are wallet counts, and one person can run many wallets. But the shape is unmistakable: a thin layer of insiders and "professionals" at the top, and a large base of ordinary people paying for the game.&lt;/p&gt;

&lt;p&gt;An earlier study by Solidus Labs found that of more than 7 million pump.fun tokens with at least five trades, 98.6% had collapsed below $1,000 in liquidity (&lt;a href="https://thedefiant.io/alarming-99-of-memecoin-launches-on-pumpfun-are-pump-and-dumps-or-rug-pulls-report" rel="noopener noreferrer"&gt;The Defiant&lt;/a&gt;). Not every one of those was a deliberate scam. But a market where 98.6% of products collapse is not a market. It's a lottery with a fee on every ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first block
&lt;/h2&gt;

&lt;p&gt;If the odds were merely bad, you could call it gambling and move on. The deeper problem is that the game is often decided before a normal person can even click "buy."&lt;/p&gt;

&lt;p&gt;On Solana, a token's creator, or a bot watching for new launches, can buy in the very same block the token is created. Pine Analytics found that this kind of same-block sniping is no longer an edge case but the dominant launch pattern on pump.fun. Looking only at the most obvious form of collusion, snipers funded directly by the token's own deployer, it accounted for about 1.75% of all launches. That is a floor: insiders who route funds through a few extra wallets slip past the method (&lt;a href="https://pineanalytics.substack.com/p/exit-liquidity-machines" rel="noopener noreferrer"&gt;Pine Analytics&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;An entire industry has grown up to serve this. "Bundler" tools, advertised openly, let a launcher buy from up to 20 wallets in the creation block, and many launches use between 20 and 50 (&lt;a href="https://www.thecoinrepublic.com/2026/09/25/best-solana-bundler-in-2026-4-pump-fun-and-raydium-bundlers-compared/" rel="noopener noreferrer"&gt;The Coin Republic&lt;/a&gt;). The supply is spread across fresh wallets so that it looks organic. Then it is sold to whoever arrives next.&lt;/p&gt;

&lt;p&gt;By the time a token appears in your feed, the cheapest supply has usually been claimed by software. The retail buyer is not a participant. The retail buyer is the exit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it did to crypto
&lt;/h2&gt;

&lt;p&gt;The damage doesn't stay on pump.fun. For two years, it set the tone for what a "crypto app" is. Attention, liquidity, and talent flowed toward launching and flipping tokens rather than building things people use. New users arrived through a casino, lost money, and left believing that this is what crypto is.&lt;/p&gt;

&lt;p&gt;The platform's culture made it worse. In late 2024, pump.fun had to shut down livestreaming after creators broadcast animal cruelty, threats of violence, and self-harm to pump their tokens (&lt;a href="https://decrypt.co/303790?p=303790" rel="noopener noreferrer"&gt;Decrypt&lt;/a&gt;). It was also reportedly geo-blocked in the UK after action by the Financial Conduct Authority (&lt;a href="https://www.mitrade.com/th/insights/news/live-news/article-3-1840948-20260625" rel="noopener noreferrer"&gt;Mitrade&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;And the activity it generated proved hollow. When the memecoin tide went out in 2026, daily Solana network fees fell about 84% between January and June, and pump.fun's own graduation rate dropped 80% in three months (&lt;a href="https://www.dextools.io/news/pump-fun-graduation-collapse-solana-fees-2026" rel="noopener noreferrer"&gt;DEXTools&lt;/a&gt;). Growth built on extraction doesn't compound. It just ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lawsuit
&lt;/h2&gt;

&lt;p&gt;Pump.fun's operator, Baton Corporation, and its three founders are defendants in a federal class action in New York. The plaintiffs estimate retail losses at $4 billion to $5.5 billion, a figure that has not been tested in court (&lt;a href="https://decrypt.co/331528/solana-pump-fun-amended-rico-suit-alleging-meme-coin-gambling" rel="noopener noreferrer"&gt;Decrypt&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;On August 31, 2026, Judge Colleen McMahon split her ruling. She dismissed the claims that pump.fun tokens were unregistered securities, rejected the theory that trading memecoins counts as illegal gambling under New York law, and cleared Solana Labs, the Solana Foundation and their executives (&lt;a href="https://solanafloor.com/news/all-claims-against-solana-labs-and-foundation-dismissed" rel="noopener noreferrer"&gt;SolanaFloor&lt;/a&gt;). But she let the racketeering (RICO) claims proceed against Baton and its founders personally (&lt;a href="https://x.com/BurwickLaw/status/2099556497109696689" rel="noopener noreferrer"&gt;Burwick Law&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Nothing has been proven yet. But a federal judge has found the racketeering allegations against the people running pump.fun detailed enough to go forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Their defense, answered
&lt;/h2&gt;

&lt;p&gt;Pump.fun's defenders make four arguments. Each deserves a straight answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"It's permissionless. Adults choose to play."&lt;/strong&gt; Choice requires information. A buyer who doesn't know that about 2 in 1,000 tokens graduate, that most die on day one, and that the cheapest supply was often taken by software in the first block is not making an informed choice. Permissionless shouldn't mean rigged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"They're reforming."&lt;/strong&gt; To their credit pump.fun has shipped changes, including cashback for traders and BOOST, a launch mechanism that briefly lifted the daily graduation rate to 6.7% in July 2026 (&lt;a href="https://theblock.co/post/409815/pump-fun-token-graduation-rate-jumps-boost-changes-launch-incentives" rel="noopener noreferrer"&gt;The Block&lt;/a&gt;). Better odds are welcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"It brought millions of users to Solana."&lt;/strong&gt; It did. Most of them left with losses, and the activity evaporated once the hype did. Onboarding people into a machine that takes their money isn't adoption. It's burning the users the industry will need later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"PUMP holders benefit from buybacks."&lt;/strong&gt; They do, but it's not sustainable. The token's support comes from fees paid by traders who mostly lose. The platform itself states that PUMP carries no right to its revenue (&lt;a href="https://defillama.com/token/pump" rel="noopener noreferrer"&gt;DefiLlama&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;To be honest, I've barely used pump.fun. This isn't the story of a burned trader. I'm joining the boycott because a company earning hundreds of millions of dollars responds to one kind of pressure above all: people choosing not to use it.&lt;/p&gt;

&lt;p&gt;I also want to give credit where it's due. The bonding curve is genuinely a good idea. It gives every token open price discovery from the first trade, with no insider-arranged liquidity. With real protections, such as limits on first-block buys, vesting for creators, and a visible history for every deployer, it could be a strong tool for ICOs and community funding.&lt;/p&gt;

&lt;p&gt;That isn't how it's used. People come to pump.fun to find the next WIF, or to ride the pump and get out before the dump. The platform is built around that behavior. It takes a fee on all of it, and gives remarkably little back to the communities that generate it.&lt;/p&gt;

&lt;p&gt;Competition won't fix this on its own, because pump.fun is the template. It showed every launchpad that came after it how to make hundreds of millions while not caring what happens to users. It has given a home to serial deployers who pulled tens of millions of dollars out of traders. That lesson is spreading, and it has tainted the whole industry.&lt;/p&gt;

&lt;p&gt;I believe enough pressure can change the product. I'm far less convinced it can change the people running it, and that matters most. Products follow incentives, and a boycott changes incentives. But culture comes from leadership, which is why accountability for the people in charge, including in court, matters as much as any new feature.&lt;/p&gt;

&lt;p&gt;Crypto's promise was a fairer financial system. Pump.fun took a good mechanism and built a casino on top of it. I'd like to see the bonding curve outlive the casino, and the only way that happens is if we stop feeding it.&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>solana</category>
    </item>
    <item>
      <title>Ministable: a CDP engine and a stablecoin in one contract</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Fri, 23 Oct 2026 15:16:21 +0000</pubDate>
      <link>https://dev.to/rabuawad/ministable-a-cdp-engine-and-a-stablecoin-in-one-contract-1p7b</link>
      <guid>https://dev.to/rabuawad/ministable-a-cdp-engine-and-a-stablecoin-in-one-contract-1p7b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"We believe that stable digital assets [...] are essential to realizing the full potential of blockchain technology." (The Maker Protocol whitepaper)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the last few days, I've been working on a new project called &lt;strong&gt;ministable&lt;/strong&gt;. It started with a simple question: can you fit an entire CDP engine &lt;em&gt;and&lt;/em&gt; the stablecoin it issues into a single smart contract? That was the whole premise. It turns out you can.&lt;/p&gt;

&lt;p&gt;I'd been reading a lot about stablecoins: how they're designed and what each design trades away. One thing kept bothering me. Years after the Terra/LUNA collapse, no decentralized stablecoin has come close to the scale of USDT or USDC. So I started digging into the designs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a CDP?
&lt;/h2&gt;

&lt;p&gt;A CDP (collateralized debt position) is a loan you take out against your own crypto. You lock collateral in a contract, for example, ETH, and mint stablecoins against it. You always have to lock more value than you borrow. To get your collateral back, you repay the stablecoins you minted plus interest.&lt;/p&gt;

&lt;p&gt;If the price of your collateral drops and your position falls below the required ratio, anyone can liquidate it. They repay part of your debt and receive some of your collateral at a discount. That's what keeps every stablecoin in circulation backed by more than a dollar of collateral.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspiration: DAI and Microstable
&lt;/h2&gt;

&lt;p&gt;Ministable is inspired by two projects: &lt;strong&gt;DAI&lt;/strong&gt; from MakerDAO and &lt;strong&gt;Microstable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;DAI is the original decentralized, crypto-backed stablecoin. It's widely accepted, widely used, and has a lot of unique properties. The first version, Single-Collateral DAI, was backed only by ETH, and that's the version ministable is closest to. Reading the DAI whitepaper, I was struck by how simple and useful the core idea is.&lt;/p&gt;

&lt;p&gt;Building a stablecoin isn't easy, though. You can build something that technically holds its peg. The hard part is building something that &lt;em&gt;scales&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;DAI is the king of decentralized stablecoins (I'm counting DAI and USDS as one). Plenty of protocols have tried to take its place, and so far they've all failed. But even DAI has a scaling problem. It's huge compared to any other decentralized stablecoin, yet I don't see it overtaking USDC or USDT. Overcollateralization is part of the reason: every dollar of DAI needs more than a dollar of crypto locked behind it, so supply is limited by how much collateral people are willing to lock up.&lt;/p&gt;

&lt;p&gt;Still, the design is solid and worth exploring onchain. So I set out to build a stablecoin engine and its token in a single contract, and thanks to Vyper's module system, I could.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ministable: mUSD
&lt;/h2&gt;

&lt;p&gt;The first ministable deployment is &lt;strong&gt;mUSD&lt;/strong&gt;, a stablecoin pegged to the US dollar and backed by ETH. Like everything else in this project, the design is minimal, and it works like any other CDP-backed stablecoin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minting.&lt;/strong&gt; You deposit ETH and mint mUSD against it, as long as your position stays at a &lt;strong&gt;150% minimum collateral ratio&lt;/strong&gt;. That means at least $150 of ETH for every $100 of mUSD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Liquidations.&lt;/strong&gt; If your position falls below 150%, anyone can liquidate it. The liquidator repays part of your debt and gets &lt;strong&gt;110%&lt;/strong&gt; of what they repaid in ETH, which is a 10% bonus. They only repay enough to bring you back to 150%, and you keep the rest of your collateral.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redemptions.&lt;/strong&gt; Anyone can swap mUSD for &lt;strong&gt;$1 of ETH&lt;/strong&gt; from any healthy position, minus a 0.5% fee that goes to that position's owner. If mUSD trades below $1, buying it and redeeming it is profitable, so redemptions put a floor under the peg.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stability fee.&lt;/strong&gt; Debt grows over time at a fixed per-second rate, set at deployment and capped at 10% a year. The interest is charged in mUSD and minted into the protocol's &lt;strong&gt;surplus&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Surplus and bad debt.&lt;/strong&gt; If a liquidated position's collateral can't cover its debt, the shortfall becomes bad debt, and the surplus is burned to cancel it. Anyone can also buy surplus mUSD with ETH at the oracle price. That ETH goes into a &lt;strong&gt;reserve&lt;/strong&gt;, which can cover any bad debt the surplus can't.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building this taught me how hard stablecoin design really is. Every mechanism exists to close a gap left by another one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal code
&lt;/h2&gt;

&lt;p&gt;The engine and the token live in a single contract. The goal from the start was something tiny: simple to audit and simple to reason about. Without comments, the whole system (token, CDP engine, and native-ETH wrapper) is under 300 lines of Vyper, without counting the ERC-20 functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;The code has not been audited yet, and although I'm looking for money to do an audit, I think that is somewhat far away. It has undergone a few code reviews by other developers, but nothing substantial.&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>ethereum</category>
      <category>web3</category>
    </item>
    <item>
      <title>Software Was Never About Code</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Thu, 22 Oct 2026 12:53:11 +0000</pubDate>
      <link>https://dev.to/rabuawad/software-was-never-about-code-59pe</link>
      <guid>https://dev.to/rabuawad/software-was-never-about-code-59pe</guid>
      <description>&lt;p&gt;Ask an AI to build you a website, and you'll get vanilla HTML, CSS, and JavaScript. Ask for a web app, and you'll get React, probably with Next.js. Ask for a cross-platform app, and you'll get React Native. Ask for a desktop app, and you'll get Electron. The pattern holds for nearly everything that involves code: the model reaches for the most common, most widely used tool.&lt;/p&gt;

&lt;p&gt;On its own, that isn't a bad thing. Those defaults are popular for a reason. At scale, though, it's a disaster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every tool existed for a reason
&lt;/h2&gt;

&lt;p&gt;Software has so many tools because each one was built to solve something. Vue and Svelte exist because people kept running into the same problems with React. There's a long line of cross-platform frameworks because building for every platform at once has been a headache for years. Each of them started with someone who hit a limit and decided to build something better.&lt;/p&gt;

&lt;p&gt;A model doesn't hit limits that way. It reaches for what it has seen most, and what it has seen most is whatever was already popular. New tools never get enough use to become the default, so the defaults keep getting more entrenched.&lt;/p&gt;

&lt;p&gt;Follow that forward. If models keep getting smarter and costs stay roughly where they are, AI ends up writing most software. Every web app gets built with the same stack, and so does every static site and every smart contract. The huge variety of languages, frameworks and tools we had in the past stops growing. When AI can build anything faster and cheaper than any person, what's the point of building a new one?&lt;/p&gt;

&lt;h2&gt;
  
  
  Code is cheap now
&lt;/h2&gt;

&lt;p&gt;Take that one step further. If everyone uses the same models to generate the same stack, code stops being an advantage. Whatever you built, your competitor can rebuild in a fraction of the time it took you.&lt;/p&gt;

&lt;p&gt;AI hasn't made code &lt;em&gt;good&lt;/em&gt;; that's a whole other essay. But it has made code cheap, and cheap things don't set you apart.&lt;/p&gt;

&lt;p&gt;That's uncomfortable if you think of software as code. But software was never really about code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What software is actually about
&lt;/h2&gt;

&lt;p&gt;Software is distribution, marketing, getting in front of users, maintaining the product long after launch, and a lot more that has nothing to do with writing code. AI has made the code cheap, but it hasn't changed any of the rest.&lt;/p&gt;

&lt;p&gt;People use a product because they expect it to work and they expect its makers to still be maintaining it next year. That trust is as much a part of the product as the code is.&lt;/p&gt;

&lt;p&gt;Look at how many Notion copycats there are, and how many Granola copycats. Will any of them become a billion-dollar company? No. Most of the people behind them don't give a damn about the software itself. They care about the money, and getting the money takes far more than writing code. You can clone the features in a weekend. You can't clone the users, the trust, or the years of maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disposable software
&lt;/h2&gt;

&lt;p&gt;Something I find fascinating is the rise of disposable software: apps you spin up with AI in an afternoon and then forget ever existed, like a TikTok video. I'm not going to pretend I haven't done it myself.&lt;/p&gt;

&lt;p&gt;The trend is going to grow. Most of that software is harmless, because it's built for one person and one use, and then it's gone. But it changes what people value. When anyone can make an app in an afternoon, an app by itself means nothing. What means something is software that someone stands behind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The correction
&lt;/h2&gt;

&lt;p&gt;All of this is hitting the job market. A lot of engineers can't find work that pays enough for an upper-middle-class life. That's assuming they can find a job at all and get through the interview.&lt;/p&gt;

&lt;p&gt;I think a real crash is coming in tech, and it isn't about the AI bubble. The market is going to stop paying people who only produce code, because the machine produces it more cheaply. For years, producing code was enough to build a career on. It isn't anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smaller, and more elite
&lt;/h2&gt;

&lt;p&gt;I don't think we'll ever see as many software jobs as we did in 2020. But I do think the market will recover. Once the hype settles, things will stabilize, and companies will still need people.&lt;/p&gt;

&lt;p&gt;They'll need fewer people, and better ones. Programming is going to become more elitist, and only the best of the best will make meaningful money long-term. "Best" won't mean whoever solves LeetCode fastest. It will mean the people who understand the tradeoffs the machine makes, and the people who bring what the machine can't: product sense, the ability to reach users, and the commitment to keep something running for years.&lt;/p&gt;

&lt;p&gt;When every app is built on the same stack by the same models, the code is the one thing that's identical everywhere. What sets a product apart is the people behind it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
    </item>
    <item>
      <title>How USDT Actually Works: From Treasury Bills to Smart Contracts</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Mon, 19 Oct 2026 13:54:08 +0000</pubDate>
      <link>https://dev.to/rabuawad/how-usdt-actually-works-from-treasury-bills-to-smart-contracts-187p</link>
      <guid>https://dev.to/rabuawad/how-usdt-actually-works-from-treasury-bills-to-smart-contracts-187p</guid>
      <description>&lt;p&gt;USDT is one of the world's largest stablecoins, and most people who use it every day have no idea how it works. In this article, we'll look at it from both ends: the business model that keeps it pegged to the dollar, and the smart contract that makes it move onchain. By the end, you'll have built your own version of USDT in Vyper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tether vs. USDT
&lt;/h2&gt;

&lt;p&gt;First, the names. &lt;strong&gt;Tether&lt;/strong&gt; is the company. &lt;strong&gt;USDT&lt;/strong&gt; is the token it issues.&lt;/p&gt;

&lt;p&gt;Tether manages the reserves that, in theory, back every USDT in existence across every chain it lives on: Ethereum, Tron, Solana, and many others. Each USDT is supposed to be redeemable for one US dollar, and Tether's reserves are what make that promise credible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the money actually goes
&lt;/h2&gt;

&lt;p&gt;This is where it gets interesting. Tether doesn't keep a giant pile of dollars in a vault. Most of its reserves are held in &lt;strong&gt;US Treasury bills&lt;/strong&gt;, which are short-term debt issued by the US government. The rest is a mix of cash equivalents, gold, Bitcoin, and secured loans.&lt;/p&gt;

&lt;p&gt;The scale is huge. Tether is one of the largest holders of US government debt in the world, ranking alongside entire countries. It has said it was among the top buyers of US Treasuries, competing with nations like Germany and South Korea.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's a Treasury bill?
&lt;/h3&gt;

&lt;p&gt;A Treasury bill (T-bill) is a short-term loan to the US government, maturing in one year or less. T-bills don't pay coupons. You buy them at a discount and receive the full face value at maturity, and the difference is your interest.&lt;/p&gt;

&lt;p&gt;For example, you might pay $95,000 for a T-bill that pays you $100,000 a year later. That $5,000 is your return.&lt;/p&gt;

&lt;p&gt;T-bills are considered about as close to risk-free as an investment gets, and they're highly liquid. That matters for a stablecoin: if many people want to redeem USDT at once, Tether needs to turn its reserves into cash quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The business model
&lt;/h2&gt;

&lt;p&gt;Look at this from Tether's side. People hand Tether dollars to get USDT, and USDT pays them no interest. Tether takes those dollars, buys T-bills, and keeps the yield.&lt;/p&gt;

&lt;p&gt;With over a hundred billion dollars in reserves, even a 4–5% yield adds up to billions per year. That's why Tether is one of the most profitable companies in the world per employee. It reported roughly $10 billion in net profit in 2025, and it has a relatively small team.&lt;/p&gt;

&lt;p&gt;It's a brilliant model. You create a digital dollar that people around the world use to save and transact, and in return you slowly build one of the largest Treasury portfolios on the planet.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about fees?
&lt;/h3&gt;

&lt;p&gt;If you've ever sent USDT, you've noticed that sending 1 USDT means the recipient gets 1 USDT. The gas fee goes to the blockchain's validators, not to Tether. So Tether doesn't earn anything from everyday transfers.&lt;/p&gt;

&lt;p&gt;Where Tether &lt;em&gt;does&lt;/em&gt; charge fees is at the edges of the system: &lt;strong&gt;minting and redemption&lt;/strong&gt;. Regular users don't deal with Tether directly. Large, verified institutions such as exchanges, market makers, and payment companies deposit dollars to mint new USDT, or send USDT back to redeem dollars. Tether charges a small percentage fee on these operations and requires high minimums. It's a nice revenue stream, but the real money comes from the reserves.&lt;/p&gt;

&lt;p&gt;Tether has other products and investments that we won't cover here. If you're curious, check out &lt;a href="https://tether.to/" rel="noopener noreferrer"&gt;tether.to&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The catch: it's centralized
&lt;/h2&gt;

&lt;p&gt;Everything above depends on trusting Tether. The peg holds because the market believes Tether actually has the reserves and will honor redemptions. Tether publishes quarterly &lt;strong&gt;attestations&lt;/strong&gt; of its reserves, prepared by an accounting firm. But an attestation is a snapshot of holdings on a given date, not a full audit, and Tether has faced criticism over the years about transparency.&lt;/p&gt;

&lt;p&gt;The smart contract reflects this centralization too. As we'll see, Tether can mint tokens, burn them, pause the contract, and freeze specific addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going to the source code
&lt;/h2&gt;

&lt;p&gt;Now for the fun part. We'll look at USDT's &lt;a href="https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code" rel="noopener noreferrer"&gt;Ethereum implementation&lt;/a&gt; and rebuild it ourselves in &lt;a href="https://vyperlang.org/" rel="noopener noreferrer"&gt;Vyper&lt;/a&gt;, a Pythonic language for writing Ethereum smart contracts.&lt;/p&gt;

&lt;p&gt;If you're new to programming or Ethereum, don't worry. We'll go step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  USDT is (mostly) an ERC20
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ERC20&lt;/strong&gt; is the Ethereum standard for fungible tokens. It's a small interface: six core functions (&lt;code&gt;totalSupply&lt;/code&gt;, &lt;code&gt;balanceOf&lt;/code&gt;, &lt;code&gt;transfer&lt;/code&gt;, &lt;code&gt;transferFrom&lt;/code&gt;, &lt;code&gt;approve&lt;/code&gt;, &lt;code&gt;allowance&lt;/code&gt;), three optional metadata functions (&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;symbol&lt;/code&gt;, &lt;code&gt;decimals&lt;/code&gt;), and two events (&lt;code&gt;Transfer&lt;/code&gt;, &lt;code&gt;Approval&lt;/code&gt;). Any contract that implements this interface can be held in wallets, traded on exchanges, and shown on block explorers as a token.&lt;/p&gt;

&lt;p&gt;Here's a fun detail: the USDT contract on Ethereum &lt;strong&gt;isn't fully ERC20-compliant&lt;/strong&gt;. It was written in 2017 in an old version of Solidity, and its &lt;code&gt;transfer&lt;/code&gt; and &lt;code&gt;transferFrom&lt;/code&gt; functions don't return a &lt;code&gt;bool&lt;/code&gt; as the standard requires. This has broken many DeFi integrations over the years, and it's the reason libraries like OpenZeppelin's &lt;code&gt;SafeERC20&lt;/code&gt; exist. We'll come back to this when we write our own version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the project
&lt;/h3&gt;

&lt;p&gt;We'll keep the setup minimal. We'll use &lt;a href="https://docs.astral.sh/uv/getting-started/installation/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; to manage dependencies and &lt;a href="https://titanoboa.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Titanoboa&lt;/a&gt; to compile and test our Vyper code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install uv.&lt;/li&gt;
&lt;li&gt;Create the project: &lt;code&gt;uv init &amp;lt;project_name&amp;gt;&lt;/code&gt;, move into it with &lt;code&gt;cd &amp;lt;project_name&amp;gt;&lt;/code&gt;, then delete the generated &lt;code&gt;main.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a virtual environment: &lt;code&gt;uv venv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Activate it:

&lt;ul&gt;
&lt;li&gt;Linux/macOS: &lt;code&gt;source .venv/bin/activate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows: &lt;code&gt;.venv\Scripts\activate&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Install Titanoboa: &lt;code&gt;uv add titanoboa&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install pytest for testing: &lt;code&gt;uv add --dev pytest&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Titanoboa installs the Vyper compiler as a dependency. This article uses &lt;strong&gt;Vyper 0.4.3&lt;/strong&gt;, and every file starts with &lt;code&gt;# pragma version ==0.4.3&lt;/code&gt; to pin it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;project_name&amp;gt;/
├── modules/          # reusable modules
│   ├── erc20.vy
│   ├── ownable.vy
│   ├── pausable.vy
│   └── blacklist.vy
├── contracts/        # smart contracts
│   └── usdt.vy
├── tests/            # tests
│   └── test_usdt.py
└── pyproject.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A quick word on modules
&lt;/h3&gt;

&lt;p&gt;Solidity reuses code through &lt;strong&gt;inheritance&lt;/strong&gt;. The original USDT is a tower of contracts: &lt;code&gt;TetherToken&lt;/code&gt; inherits from &lt;code&gt;Pausable&lt;/code&gt;, &lt;code&gt;StandardToken&lt;/code&gt; and &lt;code&gt;BlackList&lt;/code&gt;, which in turn inherit from &lt;code&gt;Ownable&lt;/code&gt; and &lt;code&gt;BasicToken&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vyper takes a different approach: &lt;strong&gt;modules&lt;/strong&gt;. A module is a regular &lt;code&gt;.vy&lt;/code&gt; file with state and functions that a contract can import and reuse. There are no &lt;code&gt;virtual&lt;/code&gt; or &lt;code&gt;override&lt;/code&gt; keywords. Instead, a contract chooses which of a module's external functions to &lt;strong&gt;export&lt;/strong&gt; into its own ABI. If it needs different behavior, it skips the export and writes its own version on top of the module's internal helpers.&lt;/p&gt;

&lt;p&gt;We'll build four modules, one for each piece of the original contract, and then assemble them into the token.&lt;/p&gt;

&lt;h3&gt;
  
  
  ERC20
&lt;/h3&gt;

&lt;p&gt;The first module holds the token's books: who owns how much (&lt;code&gt;_balances&lt;/code&gt;), who may spend whose tokens (&lt;code&gt;_allowances&lt;/code&gt;), and how many tokens exist (&lt;code&gt;_total_supply&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It has two layers. The standard ERC20 functions are external, so any contract can export them as they are. The real logic lives in internal functions (&lt;code&gt;_transfer&lt;/code&gt;, &lt;code&gt;_approve&lt;/code&gt;, &lt;code&gt;_spend_allowance&lt;/code&gt;, &lt;code&gt;_mint&lt;/code&gt;, &lt;code&gt;_burn&lt;/code&gt;) that other contracts can build on. That split will matter when USDT adds its own rules to &lt;code&gt;transfer&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# modules/erc20.vy
# pragma version ==0.4.3
# pragma nonreentrancy on
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
@title ERC20
@notice Minimal ERC20 accounting module. Holds balances, allowances
        and total supply, and exposes the standard ERC20 functions.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ethereum.ercs&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;IERC20&lt;/span&gt;
&lt;span class="n"&gt;implements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IERC20&lt;/span&gt;


&lt;span class="n"&gt;_balances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;_allowances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;_total_supply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;


&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_balances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_allowances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_total_supply&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_spend_allowance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_allowances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;IERC20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Approval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;erc20: transfer to zero address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# Vyper arithmetic is checked: this reverts if the balance is too low.
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_balances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_balances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;IERC20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_spend_allowance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_allowances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# An allowance of max_value(uint256) is treated as infinite.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;max_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_allowances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;erc20: mint to zero address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_balances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_total_supply&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;IERC20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_burn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_balances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_total_supply&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;IERC20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth noticing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;SafeMath&lt;/code&gt;.&lt;/strong&gt; The 2017 USDT contract needed a &lt;code&gt;SafeMath&lt;/code&gt; library to guard against overflows. Vyper checks all arithmetic by default, so &lt;code&gt;self._balances[sender] -= amount&lt;/code&gt; simply reverts if the sender doesn't have enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;implements: IERC20&lt;/code&gt;&lt;/strong&gt; makes the compiler check that we match the standard, including returning &lt;code&gt;bool&lt;/code&gt; from &lt;code&gt;transfer&lt;/code&gt; and &lt;code&gt;transferFrom&lt;/code&gt;. With this line, the compiler would have caught the original USDT's missing return value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minting is a transfer from the zero address, and burning is a transfer to it.&lt;/strong&gt; This is the standard way to log supply changes, and block explorers rely on these &lt;code&gt;Transfer&lt;/code&gt; events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;# pragma nonreentrancy on&lt;/code&gt;&lt;/strong&gt; puts a reentrancy lock on every external function. Our token never calls other contracts, but it's a sensible default that costs us nothing to turn on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Ownable
&lt;/h3&gt;

&lt;p&gt;USDT is centralized, and this is the module that makes it so. &lt;code&gt;Ownable&lt;/code&gt; stores one address, the &lt;code&gt;owner&lt;/code&gt;, and gives other code a way to say "only the owner can do this."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# modules/ownable.vy
# pragma version ==0.4.3
# pragma nonreentrancy on
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
@title Ownable
@notice Single-owner access control. Other modules call `_check_owner()`
        to restrict functions to the owner.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;OwnershipTransferred&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;previous_owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;new_owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@deploy&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_transfer_ownership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transferOwnership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;new_owner&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ownable: new owner is zero address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_transfer_ownership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ownable: caller is not the owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_transfer_ownership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;previous_owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_owner&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;OwnershipTransferred&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;previous_owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;new_owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@deploy&lt;/code&gt; marks the constructor. It runs once, when the contract is deployed, and makes the deployer the owner. &lt;code&gt;public(address)&lt;/code&gt; tells Vyper to generate an &lt;code&gt;owner()&lt;/code&gt; getter for us.&lt;/p&gt;

&lt;p&gt;Solidity uses an &lt;code&gt;onlyOwner&lt;/code&gt; modifier here. Vyper has no modifiers, so we call &lt;code&gt;_check_owner()&lt;/code&gt; on the first line of each restricted function. It's more explicit, and you can see every check when you read the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pausable
&lt;/h3&gt;

&lt;p&gt;Pausable is an emergency brake. If something goes wrong, such as a hack or a bug, the owner can freeze all transfers at once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# modules/pausable.vy
# pragma version ==0.4.3
# pragma nonreentrancy on
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
@title Pausable
@notice Emergency stop switch controlled by the owner.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ownable&lt;/span&gt;
&lt;span class="n"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ownable&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Unpause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;


&lt;span class="n"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pausable: already paused&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Pause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;unpause&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pausable: not paused&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Unpause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_require_not_paused&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pausable: paused&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key line is &lt;strong&gt;&lt;code&gt;uses: ownable&lt;/code&gt;&lt;/strong&gt;. Pausable needs to read the owner, but it shouldn't &lt;em&gt;own&lt;/em&gt; the &lt;code&gt;Ownable&lt;/code&gt; state. If it did, our final contract could end up with two owners. &lt;code&gt;uses&lt;/code&gt; means "I depend on a module that someone else will initialize." When we assemble the token, we'll tell the compiler which &lt;code&gt;ownable&lt;/code&gt; to plug in.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;_require_not_paused()&lt;/code&gt; is the hook the token will call at the start of &lt;code&gt;transfer&lt;/code&gt; and &lt;code&gt;transferFrom&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  BlackList
&lt;/h3&gt;

&lt;p&gt;This is the feature people talk about most. Tether can &lt;strong&gt;freeze&lt;/strong&gt; any address, and it does so regularly, often at the request of law enforcement. The original contract can also &lt;strong&gt;destroy&lt;/strong&gt; the funds of a blacklisted address, which removes those tokens from circulation. Tether can then reissue them elsewhere, for example to the victim of a hack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# modules/blacklist.vy
# pragma version ==0.4.3
# pragma nonreentrancy on
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
@title BlackList
@notice Lets the owner freeze addresses and destroy the funds they hold.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ownable&lt;/span&gt;
&lt;span class="n"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ownable&lt;/span&gt;


&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;erc20&lt;/span&gt;
&lt;span class="n"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;erc20&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;AddedBlackList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;RemovedBlackList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;DestroyedBlackFunds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;


&lt;span class="n"&gt;is_black_listed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;isBlackListed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_black_listed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;addBlackList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_black_listed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;AddedBlackList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;removeBlackList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_black_listed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;RemovedBlackList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;destroyBlackFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_black_listed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blacklist: account not blacklisted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_balances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_burn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;DestroyedBlackFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_require_not_blacklisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_black_listed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blacklist: account is blacklisted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This module &lt;code&gt;uses&lt;/code&gt; two modules. It needs &lt;code&gt;ownable&lt;/code&gt; for access control and &lt;code&gt;erc20&lt;/code&gt; so that &lt;code&gt;destroyBlackFunds&lt;/code&gt; can read a balance and burn it.&lt;/p&gt;

&lt;p&gt;Notice the two naming styles. Inside the module, the storage variable is &lt;code&gt;is_black_listed&lt;/code&gt;, in Python-style snake_case. But the external functions and events (&lt;code&gt;isBlackListed&lt;/code&gt;, &lt;code&gt;addBlackList&lt;/code&gt;, &lt;code&gt;destroyBlackFunds&lt;/code&gt;, and so on) keep the camelCase names of the original contract. The explicit &lt;code&gt;isBlackListed&lt;/code&gt; getter is the bridge between the two.&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;destroyBlackFunds&lt;/code&gt; only works on an address that is already blacklisted. Tether has to freeze the funds before it can destroy them.&lt;/p&gt;

&lt;h3&gt;
  
  
  USDT Token
&lt;/h3&gt;

&lt;p&gt;Now we bring all the modules together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# contracts/usdt.vy
# pragma version ==0.4.3
# pragma nonreentrancy on
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
@title Tether USD (Vyper edition)
@notice An educational rebuild of the USDT Ethereum contract: an ERC20
        token that the owner can issue, redeem, pause and freeze.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ethereum.ercs&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;IERC20&lt;/span&gt;
&lt;span class="n"&gt;implements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IERC20&lt;/span&gt;


&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ethereum.ercs&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;IERC20Detailed&lt;/span&gt;
&lt;span class="n"&gt;implements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IERC20Detailed&lt;/span&gt;


&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..modules&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ownable&lt;/span&gt;
&lt;span class="n"&gt;initializes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ownable&lt;/span&gt;


&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..modules&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;erc20&lt;/span&gt;
&lt;span class="n"&gt;initializes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;erc20&lt;/span&gt;


&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..modules&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pausable&lt;/span&gt;
&lt;span class="n"&gt;initializes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pausable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ownable&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;..modules&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;blacklist&lt;/span&gt;
&lt;span class="n"&gt;initializes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blacklist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ownable&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;erc20&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transferOwnership&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;pausable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;pausable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;pausable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unpause&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;blacklist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isBlackListed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;blacklist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addBlackList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;blacklist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removeBlackList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;blacklist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;destroyBlackFunds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Redeem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;


&lt;span class="nd"&gt;@deploy&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_supply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_supply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tether USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USDT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;pausable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_require_not_paused&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;blacklist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_require_not_blacklisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;pausable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_require_not_paused&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;blacklist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_require_not_blacklisted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_spend_allowance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Same rule as the original USDT: to change a non-zero allowance you
&lt;/span&gt;    &lt;span class="c1"&gt;# must first set it to zero. This mitigates the approve front-running
&lt;/span&gt;    &lt;span class="c1"&gt;# race, but it's also why `approve` on USDT trips up many integrations.
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_allowances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usdt: reset allowance to zero first&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @notice Mint new tokens to the owner. In practice this happens after an
            institution has wired dollars to Tether.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;redeem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @notice Burn tokens from the owner&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s balance, e.g. after an institution
            has sent USDT back to Tether in exchange for dollars.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;erc20&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_burn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ownable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Redeem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go through it piece by piece.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;initializes&lt;/code&gt;&lt;/strong&gt; says this contract owns the state of each module and is responsible for setting it up. This is where the &lt;code&gt;uses&lt;/code&gt; dependencies get wired together. &lt;code&gt;pausable[ownable := ownable]&lt;/code&gt; means "the &lt;code&gt;ownable&lt;/code&gt; that Pausable depends on is &lt;em&gt;this&lt;/em&gt; &lt;code&gt;ownable&lt;/code&gt;." As a result, the whole contract shares a single owner and a single set of balances. The compiler checks this wiring for you. If you forget to initialize a module, or initialize one twice, the contract won't compile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;exports&lt;/code&gt;&lt;/strong&gt; picks which module functions become part of the token's public ABI. The getters and admin functions are exported as they are. Notice that &lt;code&gt;erc20.transfer&lt;/code&gt;, &lt;code&gt;erc20.transferFrom&lt;/code&gt; and &lt;code&gt;erc20.approve&lt;/code&gt; are &lt;em&gt;not&lt;/em&gt; exported.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We write our own &lt;code&gt;transfer&lt;/code&gt;, &lt;code&gt;transferFrom&lt;/code&gt; and &lt;code&gt;approve&lt;/code&gt;&lt;/strong&gt; because USDT needs extra rules before a transfer goes through:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The contract must not be paused.&lt;/li&gt;
&lt;li&gt;The sender (or, for &lt;code&gt;transferFrom&lt;/code&gt;, the token owner) must not be blacklisted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After those checks, we hand off to the ERC20 module's internal &lt;code&gt;_transfer&lt;/code&gt;. Checking the &lt;em&gt;token owner&lt;/em&gt; in &lt;code&gt;transferFrom&lt;/code&gt; matters. Otherwise a frozen address could approve a friend, and the friend could move the funds out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;approve&lt;/code&gt; quirk.&lt;/strong&gt; The real USDT refuses to change an allowance from one non-zero value to another. You must set it to &lt;code&gt;0&lt;/code&gt; first. This is meant to block a front-running attack on &lt;code&gt;approve&lt;/code&gt;, and it's another famous source of broken integrations. We kept it so our token behaves like the real one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;issue&lt;/code&gt; and &lt;code&gt;redeem&lt;/code&gt;&lt;/strong&gt; are the onchain side of the business model. When an institution wires dollars to Tether, Tether calls &lt;code&gt;issue&lt;/code&gt; to mint fresh USDT to its own treasury and then sends the tokens to the customer. When the customer sends USDT back for dollars, Tether calls &lt;code&gt;redeem&lt;/code&gt; to burn them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we left out.&lt;/strong&gt; The real contract has two more features that we skipped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transfer fee:&lt;/strong&gt; &lt;code&gt;basisPointsRate&lt;/code&gt; and &lt;code&gt;maximumFee&lt;/code&gt; allow a fee on every transfer. It has always been set to zero, which is why, as we saw earlier, Tether earns nothing from transfers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgrade:&lt;/strong&gt; &lt;code&gt;deprecate&lt;/code&gt; and &lt;code&gt;upgradedAddress&lt;/code&gt; let Tether point all calls to a new contract.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What we did differently.&lt;/strong&gt; Our &lt;code&gt;transfer&lt;/code&gt; and &lt;code&gt;transferFrom&lt;/code&gt; return &lt;code&gt;bool&lt;/code&gt;, as ERC20 requires, so our token works with any DeFi protocol without special wrappers. Our &lt;code&gt;issue&lt;/code&gt; also emits a standard &lt;code&gt;Transfer&lt;/code&gt; event, which the 2017 contract doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing our USDT
&lt;/h2&gt;

&lt;p&gt;Titanoboa lets us deploy the contract to a local EVM from Python and call it like a regular object. Create &lt;code&gt;tests/test_usdt.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;

&lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;  &lt;span class="c1"&gt;# 1M USDT, 6 decimals
&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eoa&lt;/span&gt;


&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bob&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contracts/usdt.vy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tether USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USDT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_transfer_insufficient_balance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_transfer_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_approve_must_reset_to_zero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usdt: reset allowance to zero first&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eoa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_issue_and_redeem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1_000&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1_000&lt;/span&gt;

    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redeem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ownable: caller is not the owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_pause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pausable: paused&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unpause&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_only_owner_can_pause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ownable: caller is not the owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_blacklist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addBlackList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isBlackListed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Alice can't send...
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blacklist: account is blacklisted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# ...and nobody can move her funds with an allowance either.
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blacklist: account is blacklisted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeBlackList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_destroy_black_funds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blacklist: account not blacklisted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroyBlackFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addBlackList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroyBlackFunds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;INITIAL_SUPPLY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_transfer_ownership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transferOwnership&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ownable: caller is not the owner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;usdt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few Titanoboa tools do most of the work here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;boa.load&lt;/code&gt; compiles the contract and deploys it, passing &lt;code&gt;INITIAL_SUPPLY&lt;/code&gt; to the constructor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;boa.env.eoa&lt;/code&gt; is the default account that sends our transactions, so it's also the deployer and owner.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;boa.env.prank(alice)&lt;/code&gt; sends the calls inside the &lt;code&gt;with&lt;/code&gt; block as Alice.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;boa.reverts("...")&lt;/code&gt; checks that a call fails with the expected error message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run the suite from the project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pytest
...........                                                              [100%]
11 passed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Strip away the billions of dollars, and USDT is a surprisingly small program. It's an ERC20 token with four admin powers: &lt;strong&gt;issue&lt;/strong&gt;, &lt;strong&gt;redeem&lt;/strong&gt;, &lt;strong&gt;pause&lt;/strong&gt; and &lt;strong&gt;blacklist&lt;/strong&gt;. Every one of them belongs to a single owner.&lt;/p&gt;

&lt;p&gt;That's the whole story in code. The token is only worth a dollar because Tether holds T-bills offchain and honors redemptions, and the contract gives Tether complete control over who can hold and move it. Decentralized it is not, but it's one of the most successful products crypto has produced.&lt;/p&gt;

&lt;p&gt;You now have a working version of it. Some ideas to take it further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the transfer fee (&lt;code&gt;basisPointsRate&lt;/code&gt; and &lt;code&gt;maximumFee&lt;/code&gt;) from the original contract.&lt;/li&gt;
&lt;li&gt;Replace the single owner with multiple roles, for example, separate minter, pauser, and blacklister addresses, the way newer stablecoins do.&lt;/li&gt;
&lt;li&gt;Deploy it to a testnet and add it to your wallet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just don't expect it to hold its peg without a hundred billion dollars in Treasury bills behind it.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>cryptocurrency</category>
      <category>solidity</category>
    </item>
    <item>
      <title>How to detect if an address is a smart contract using Vyper</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Thu, 15 Oct 2026 14:19:48 +0000</pubDate>
      <link>https://dev.to/rabuawad/how-to-detect-if-an-address-is-a-smart-contract-using-vyper-2685</link>
      <guid>https://dev.to/rabuawad/how-to-detect-if-an-address-is-a-smart-contract-using-vyper-2685</guid>
      <description>&lt;h2&gt;
  
  
  1. Setup
&lt;/h2&gt;

&lt;p&gt;For this guide, we'll use a minimal setup with &lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; as the dependency manager and &lt;a href="https://github.com/vyperlang/titanoboa" rel="noopener noreferrer"&gt;Titanoboa&lt;/a&gt; to compile and test Vyper contracts.&lt;/p&gt;

&lt;p&gt;If you're unfamiliar with Vyper, it's an EVM programming language with Python-like syntax. It's simple and direct, making it a great choice for developing efficient and secure smart contracts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the project
&lt;/h3&gt;

&lt;p&gt;Initialize a new project with &lt;code&gt;uv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init &amp;lt;project_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a virtual environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Titanoboa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv add titanoboa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ready!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Vyper Built-in Features
&lt;/h2&gt;

&lt;p&gt;Now that Titanoboa is installed, how do we detect whether an address is a smart contract?&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;.is_contract&lt;/code&gt; Property
&lt;/h3&gt;

&lt;p&gt;All address variables in Vyper have an &lt;code&gt;.is_contract&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.is_contract → bool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns a boolean indicating whether a contract is deployed at the address.&lt;/p&gt;

&lt;p&gt;It's that simple!&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;Detector.vy&lt;/code&gt; inside a &lt;code&gt;contracts&lt;/code&gt; folder:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;contracts/Detector.vy&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pragma version ==0.4.3
&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@pure&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_target_a_contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_contract&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Let's Test It!
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;main.py&lt;/code&gt; file at the project root, write the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;main.py&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;

&lt;span class="n"&gt;USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0xC14fF56E720f79d08413CE00533256433D2ED928&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;USDC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;VITALIK_ETH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://ethereum-rpc.publicnode.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;detector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contracts/Detector.vy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_target_a_contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USDC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_target_a_contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_target_a_contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VITALIK_ETH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Problem: EIP-7702
&lt;/h3&gt;

&lt;p&gt;When performing an assertion on Vitalik's wallet, Vyper identifies it as a contract. Why?&lt;/p&gt;

&lt;p&gt;This happens because the wallet uses &lt;strong&gt;EIP-7702 delegation&lt;/strong&gt;. Technically, the account now has code, but how can we distinguish this case from a traditional smart contract?&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Special Case: EIP-7702
&lt;/h2&gt;

&lt;p&gt;To handle this, we need to inspect the code stored at the address.&lt;/p&gt;

&lt;p&gt;If the code corresponds to EIP-7702 delegation, we'll consider the address &lt;strong&gt;not to be a traditional smart contract&lt;/strong&gt;, even though &lt;code&gt;.is_contract&lt;/code&gt; may return &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The bytecode associated with EIP-7702 delegation starts with the same three bytes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0xef0100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prefix is the &lt;em&gt;delegation designator&lt;/em&gt;. It indicates that an account delegates execution to another address.&lt;/p&gt;

&lt;p&gt;We can read the address's &lt;code&gt;.code&lt;/code&gt; property to inspect these bytes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.code → Bytes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns the code associated with the address.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updated Implementation
&lt;/h3&gt;

&lt;p&gt;With this adjustment, we can distinguish between a traditional contract and an externally owned account (EOA) using EIP-7702 delegation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;contracts/Detector.vy&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pragma version ==0.4.3
&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_target_a_contract_and_not_an_eoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;_target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_contract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# EIP-7702 delegation designator
&lt;/span&gt;    &lt;span class="n"&gt;eip_7702&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ef0100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# If the first three bytes match, treat it as a delegated EOA
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;eip_7702&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why use &lt;code&gt;slice&lt;/code&gt;?&lt;/strong&gt; In Vyper, &lt;code&gt;slice&lt;/code&gt; extracts a portion of a byte sequence. Here, it reads only the first three bytes, which is sufficient to check the prefix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EIP-7702 context:&lt;/strong&gt; This EIP allows EOAs to delegate execution to smart contract code, complicating traditional contract detection methods based on code presence.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Other Detection Methods
&lt;/h2&gt;

&lt;p&gt;Although &lt;code&gt;.is_contract&lt;/code&gt; is a native Vyper property, you may encounter other approaches in older codebases or Solidity projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 1: Comparing &lt;code&gt;msg.sender&lt;/code&gt; and &lt;code&gt;tx.origin&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This approach is sometimes used to check whether the caller is an EOA or another contract.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;msg.sender == tx.origin&lt;/code&gt;, the caller is often assumed to be a regular wallet. However, this only validates the current caller; it does not let you check an arbitrary address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pragma version ==0.4.3
&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;only_humans&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# If they are equal, the caller is traditionally considered an EOA.
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relevant properties are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;msg.sender → address&lt;/code&gt;: The immediate caller of the current call.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tx.origin → address&lt;/code&gt;: The original account that initiated the transaction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; This check is not a reliable way to establish that a caller is human or that it cannot be a smart wallet. It can also break compatibility with account abstraction and smart-wallet systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 2: Checking Code Size with &lt;code&gt;.codesize&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A classic approach is to check whether the address has any code.&lt;/p&gt;

&lt;p&gt;If the code size is greater than zero, the address is traditionally considered a contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pragma version ==0.4.3
&lt;/span&gt;
&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_target_a_contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;codesize&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, code-size checks share the same EIP-7702 limitations as other methods based on detecting whether code exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Which Method Should You Use?
&lt;/h2&gt;

&lt;p&gt;For modern Vyper development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.is_contract&lt;/code&gt;&lt;/strong&gt; — The preferred option when you want a readable, direct check for whether an address has code associated with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;msg.sender == tx.origin&lt;/code&gt;&lt;/strong&gt; — Avoid using this as a general contract-detection or security mechanism. It is limited to the current caller and can break compatibility with smart wallets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.codesize &amp;gt; 0&lt;/code&gt;&lt;/strong&gt; — A classic alternative, but it has the same EIP-7702 limitations as other code-size checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspecting &lt;code&gt;.code&lt;/code&gt; for the EIP-7702 prefix&lt;/strong&gt; — Useful when your application specifically needs to distinguish delegated EOAs from traditional contracts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The key takeaway:&lt;/strong&gt; Choose your detection method based on what you actually need to establish. An address having code, being an EOA, and being controlled by a human are three different properties.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>solidity</category>
      <category>web3</category>
    </item>
    <item>
      <title>How to Implement the ERC-165 in Vyper</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Mon, 12 Oct 2026 19:57:22 +0000</pubDate>
      <link>https://dev.to/rabuawad/how-to-implement-the-erc-165-in-vyper-4i4l</link>
      <guid>https://dev.to/rabuawad/how-to-implement-the-erc-165-in-vyper-4i4l</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'preview'&lt;/p&gt;
</description>
      <category>ethereum</category>
      <category>web3</category>
      <category>solidity</category>
    </item>
    <item>
      <title>Polymarket and the oracle problem</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Mon, 12 Oct 2026 19:42:23 +0000</pubDate>
      <link>https://dev.to/rabuawad/polymarket-and-the-oracle-problem-5113</link>
      <guid>https://dev.to/rabuawad/polymarket-and-the-oracle-problem-5113</guid>
      <description>&lt;p&gt;When I first heard about Polymarket, I really liked the idea, and I still do. The fact that any future event can become tradable and, by doing so, people will put their money on what they TRULY believe will happen is actually pretty good, especially for large, important events.&lt;/p&gt;

&lt;p&gt;But most prediction markets, including Polymarket, have many flaws. The main one, and the most apparent, is the fact that the Oracle they use is not neutral.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an Oracle?
&lt;/h2&gt;

&lt;p&gt;If you are new to crypto or are not too deep into web3 lore, there is a problem called the Oracle Problem. This problem arises from the fact that blockchains are isolated systems, and getting data from the outside world is complicated, especially because you don't want to rely on a single entity to supply you with this information.&lt;/p&gt;

&lt;p&gt;A lot of products have raised millions of dollars in capital just to solve this issue. These products are known as Oracles, and their job is essentially to feed smart contracts data coming from external systems, like markets and events.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpuzvj0fdlas29yp9gda6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpuzvj0fdlas29yp9gda6.png" alt="Chainlink data-feeds diagram&lt;br&gt;
" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chainlink is a well-known one, providing price feeds and random numbers using a decentralized network of independent node operators. UMA tries to solve the oracle problem using tokenomics. UMA holders can dispute results by posting bonds at the optimistic-oracle layer, and staked UMA tokenholders vote when disputes escalate to the DVM. The core idea is simple: it is not in UMA holders' best interest to fake the data they feed to the oracle, because that would instead make the data coming from the oracle worthless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Polymarket and Bias
&lt;/h2&gt;

&lt;p&gt;Here is where this becomes a theory, but what I think is happening on markets like "MicroStrategy sells Bitcoin by May 31st" is the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1cwk5gsp91nra0ks2lmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1cwk5gsp91nra0ks2lmz.png" alt="@willo2_Poly post" width="600" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lot of UMA holders position themselves deep in the most likely outcome. In this case, on the NO side of the trade. This is a simple trade: something that has a 99% chance of happening, and if you invest $1,000,000 into it, you can easily make more than ~$10,000 almost risk-free.&lt;/p&gt;

&lt;p&gt;Key word here: almost&lt;/p&gt;

&lt;p&gt;In the unlikely scenario that the event happens (or doesn't happen, depending on the market), the losses can be devastating, transferring millions of dollars from the market. What I think is happening is that a lot of UMA whales enter these trades in order to make a few mil on the side, almost risk-free, but when things don't go their way, they favor their original position at resolution time.&lt;/p&gt;

&lt;p&gt;A WSJ-cited analysis reported that in roughly 1 in 5 disputed bets, at least one voter had a direct financial interest.&lt;/p&gt;

&lt;p&gt;The MicroStrategy facts — Important nuance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strategy did sell 32 BTC&lt;/strong&gt; between May 26 and 31 (inside the deadline).&lt;/li&gt;
&lt;li&gt;The fight was whether the resolution requires public confirmation by May 31, not just the sale occurring.&lt;/li&gt;
&lt;li&gt;Polymarket posted additional context after the June 1 8-K, stating confirmation outside the window doesn't qualify.&lt;/li&gt;
&lt;li&gt;Final DVM vote reportedly backed NO with ~98.6% of voting power.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In the MicroStrategy market, Strategy disclosed a sale that occurred before May 31, but Polymarket later clarified that confirmation outside the deadline would not count. The dispute then went to UMA tokenholders, who overwhelmingly ratified NO.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ethereum</category>
      <category>polymarket</category>
      <category>web3</category>
    </item>
    <item>
      <title>How to create your own cryptocurrency using Vyper and Python</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Thu, 08 Oct 2026 15:56:31 +0000</pubDate>
      <link>https://dev.to/rabuawad/how-to-create-your-own-cryptocurrency-using-vyper-and-python-5fab</link>
      <guid>https://dev.to/rabuawad/how-to-create-your-own-cryptocurrency-using-vyper-and-python-5fab</guid>
      <description>&lt;p&gt;Welcome. This article covers something very simple: how to create a cryptocurrency using &lt;a href="https://vyperlang.org/" rel="noopener noreferrer"&gt;Vyper&lt;/a&gt; and &lt;a href="https://www.python.org/" rel="noopener noreferrer"&gt;Python&lt;/a&gt;. This guide is designed for beginners or enthusiasts who already know a bit about blockchain and want to dive deeper.&lt;/p&gt;

&lt;p&gt;This is not an introduction to programming (we won't cover basic variables or functions) or fundamental blockchain concepts. It assumes you already understand what a cryptocurrency and a wallet address are. By the end, we will have a cryptocurrency written in Vyper ready for the Arbitrum network.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Throughout this article, I will use the terms "cryptocurrency" and "ERC20" interchangeably.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What is a Cryptocurrency? What is an ERC20?
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;ERC20&lt;/strong&gt; is the technical standard used for smart contracts on the Ethereum Virtual Machine (EVM). &lt;a href="https://eips.ethereum.org/EIPS/eip-20" rel="noopener noreferrer"&gt;EIP-20&lt;/a&gt; defines the rules a contract must follow to be considered a cryptocurrency and be compatible with exchanges and wallets.&lt;/p&gt;

&lt;p&gt;Essentially, we need to implement 6 basic functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;totalSupply&lt;/code&gt;: The total number of coins in circulation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;balanceOf&lt;/code&gt;: Shows the balance of a specific address.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transfer&lt;/code&gt;: Sends coins from the owner to a destination.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allowance&lt;/code&gt;: The amount a third party is permitted to move on behalf of the owner.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;approve&lt;/code&gt;: Authorizes an external address to move coins on behalf of the owner.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transferFrom&lt;/code&gt;: Allows an authorized address to execute the movement of funds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, we will implement 3 optional functions that improve the user experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: Name of the cryptocurrency (e.g., Bitcoin).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;symbol&lt;/code&gt;: Cryptocurrency symbol (e.g., BTC).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;decimals&lt;/code&gt;: Number of decimal places (usually 18).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We will use a minimal setup with &lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; as a dependency manager and &lt;a href="https://titanoboa.readthedocs.io/" rel="noopener noreferrer"&gt;Titanoboa&lt;/a&gt; to compile Vyper.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install UV.&lt;/li&gt;
&lt;li&gt;Create the project: &lt;code&gt;uv init &amp;lt;project_name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a virtual environment: &lt;code&gt;uv venv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Activate the environment:&lt;/li&gt;
&lt;li&gt;    Linux/macOS: &lt;code&gt;source .venv/bin/activate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;    Windows: &lt;code&gt;.venv\Scripts\activate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install Titanoboa: &lt;code&gt;uv add titanoboa&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Project Structure&lt;br&gt;
📂 &lt;em&gt;contracts/&lt;/em&gt;: Where we will store the smart contract.&lt;br&gt;
📂 &lt;em&gt;scripts/&lt;/em&gt;: Python scripts for deployment.&lt;br&gt;
📂 &lt;em&gt;tests/&lt;/em&gt;: Unit tests for our ERC20.&lt;/p&gt;


&lt;h2&gt;
  
  
  Developing our Cryptocurrency
&lt;/h2&gt;

&lt;p&gt;Create the file &lt;em&gt;contracts/ERC20.vy&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Pragma
&lt;/h3&gt;

&lt;p&gt;The pragma indicates which compiler version was used. We will use 0.4.3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pragma version ==0.4.3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing &lt;code&gt;totalSupply&lt;/code&gt; and Immutables
&lt;/h3&gt;

&lt;p&gt;We will define the name and symbol as state variables. For the total supply, we will use a public variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@deploy&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;_symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_symbol&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decimals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using &lt;code&gt;public(...)&lt;/code&gt;, Vyper automatically creates the getter function for us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing balanceOf
&lt;/h3&gt;

&lt;p&gt;We will use a HashMap to track how much each wallet holds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 It is a good idea to mark internal variables with an _ (underscore), but by using public(), Vyper handles external visibility for us efficiently.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Implementing &lt;code&gt;transfer&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The transfer function is the heart of our coin. It allows moving value from point A to point B.&lt;/p&gt;

&lt;p&gt;In Vyper, the logic is straightforward: we subtract from the sender and add to the receiver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @dev Transfers tokens to a specified address.
    @param _to The address to transfer to.
    @param _value The amount to transfer.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What is happening here?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@external&lt;/code&gt;: Allows anyone or any contract to call this function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;msg.sender&lt;/code&gt;: A global variable representing the address of whoever is executing the transaction.&lt;/li&gt;
&lt;li&gt;Extra security: Unlike older versions of other languages, Vyper natively handles overflow. If you try to send more than you have, the transaction automatically fails without extra code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Delegating Power: &lt;code&gt;approve&lt;/code&gt; and &lt;code&gt;transferFrom&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The concept of &lt;strong&gt;Allowance&lt;/strong&gt; is what makes ERC20s so powerful. It allows you to authorize an address (for example, a Decentralized Exchange) to withdraw a specific amount of tokens from your wallet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Allowance Mapping&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, we need a structure to store who has permission to withdraw from whom. We will use a nested HashMap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Owner -&amp;gt; (Spends for me -&amp;gt; Amount)
&lt;/span&gt;&lt;span class="n"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;approve&lt;/code&gt; Function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With this function, the user says: "I authorize this application to spend X amount of my tokens."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @dev Authorizes `_spender` to transfer up to `_value` tokens.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. &lt;code&gt;transferFrom&lt;/code&gt; Function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the function called by the authorized application. Note that here the sender is not the token owner, but the "spender".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @dev Moves tokens from `_from` to `_to` using the allowance mechanism.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# If there is not enough permission, Vyper will throw an overflow error
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;

    &lt;span class="c1"&gt;# Move the balances
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Events: The Final Touch
&lt;/h2&gt;

&lt;p&gt;For interfaces like MetaMask or Etherscan to show your transactions in real-time, you need &lt;strong&gt;Events&lt;/strong&gt;. Without them, the contract works, but it will be "invisible" to many applications.&lt;/p&gt;

&lt;p&gt;Add this to the top of your file, below the pragma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Approval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Make sure to call &lt;code&gt;log Transfer(...)&lt;/code&gt; and &lt;code&gt;log Approval(...)&lt;/code&gt; inside their respective functions so the standard is 100% official.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Approval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transferFrom&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have a complete and functional ERC20 contract. It is minimalist, secure, and follows Vyper 0.4.3 best practices.&lt;/p&gt;




&lt;h2&gt;
  
  
  Optimizations: Saving Gas with immutable
&lt;/h2&gt;

&lt;p&gt;If you are launching your coin on a network, every unit of gas counts. In the version we wrote above, the name, symbol, and decimals are saved in the blockchain's &lt;strong&gt;storage&lt;/strong&gt;. Reading from storage is one of the most expensive operations in terms of gas.&lt;/p&gt;

&lt;p&gt;For values that &lt;strong&gt;never change&lt;/strong&gt; after deploying the contract, Vyper offers the immutable wrapper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why use immutable?
&lt;/h3&gt;

&lt;p&gt;By marking a variable as immutable, Vyper does not save it in expensive storage space. Instead, the value is embedded directly into the contract's bytecode during deployment. This makes reading this data extremely cheap (almost free).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Optimized Code
&lt;/h3&gt;

&lt;p&gt;Here is what the implementation looks like using immutables in Vyper 0.4.3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Declare immutable variables (UPPERCASE is recommended)
&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;immutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;SYMBOL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;immutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;DECIMALS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;immutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@deploy&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;_symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="c1"&gt;# Assigned only once in the constructor
&lt;/span&gt;    &lt;span class="n"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;
    &lt;span class="n"&gt;SYMBOL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_symbol&lt;/span&gt;
    &lt;span class="n"&gt;DECIMALS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;


&lt;span class="c1"&gt;# Create external functions to comply with the ERC20 standard
&lt;/span&gt;&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;NAME&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SYMBOL&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;DECIMALS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When to use it?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;YES&lt;/strong&gt;: For the name, symbol, decimals, or an initial owner's address that will not change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NO&lt;/strong&gt;: For balances or any value you need to update in the future.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mint Implementation&lt;/p&gt;

&lt;p&gt;We implement this logic by dividing it into parts: an immutable variable to know who the smart contract creator is, an external function for access control, and an internal one for accounting logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;OWNER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;immutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@deploy&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="n"&gt;OWNER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OWNER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Only the OWNER can mint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;totalSupply&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key points of this implementation:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access Control&lt;/strong&gt;: We use assert msg.sender == OWNER to ensure no one else can arbitrarily inflate the token supply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total Supply Management&lt;/strong&gt;: Unlike a standard transfer, mint increases the self.totalSupply variable, maintaining global balance integrity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emission Convention&lt;/strong&gt;: Following best practices, we emit the Transfer event using empty(address) (the 0x00... address) as the origin. This indicates to block explorers that the tokens didn't come from another user but were just created.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logic Separation&lt;/strong&gt;: Defining _mint as an @internal function is a recommended practice. It allows us to reuse the minting logic from other contract functions in future versions without repeating code or exposing access publicly.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Adding functions like mint doesn't break compatibility with the standard. The ERC20 defines a minimum mandatory interface; as long as those base functions exist and behave as expected, you can add all the extra logic you need.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Full Code (Vyper 0.4.3)
&lt;/h2&gt;

&lt;p&gt;Here is the final, optimized contract ready for deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pragma version ==0.4.3
&lt;/span&gt;

&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;


&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;Approval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;_owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;indexed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;


&lt;span class="c1"&gt;# Immutables
&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;immutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;SYMBOL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;immutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;DECIMALS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;immutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;OWNER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;immutable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Storage Variables
&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;span class="n"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;public&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@deploy&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;_symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;
    &lt;span class="n"&gt;SYMBOL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_symbol&lt;/span&gt;
    &lt;span class="n"&gt;DECIMALS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
    &lt;span class="n"&gt;OWNER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @dev Transfers tokens to a specified address.
    @param _to The address to transfer to.
    @param _value The amount to transfer.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;approve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @dev Authorizes `_spender` to transfer up to `_value` tokens.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Approval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_spender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transferFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @dev Moves tokens from `_from` to `_to` using the allowance mechanism.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    @dev Mints `_value` amount of coins to `_to`
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OWNER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Only the OWNER can mint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;NAME&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SYMBOL&lt;/span&gt;


&lt;span class="nd"&gt;@external&lt;/span&gt;
&lt;span class="nd"&gt;@view&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;DECIMALS&lt;/span&gt;


&lt;span class="nd"&gt;@internal&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;totalSupply&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Python Script: Blockchain Deployment
&lt;/h2&gt;

&lt;p&gt;For the final touch, we will use Titanoboa (or boa), an extremely lightweight and powerful framework for deploying and testing Vyper contracts using pure Python.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Script Setup
&lt;/h3&gt;

&lt;p&gt;Create a folder called scripts/ and, inside it, a file named &lt;em&gt;deploy.py&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Install eth-account to manage our keys securely: &lt;code&gt;uv add eth-account&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Security First: The Keystore
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Golden Rule&lt;/strong&gt;: Never leave your private key in plain text in your code or in &lt;code&gt;.env&lt;/code&gt; files. It's the easiest way to get your funds stolen.&lt;/p&gt;

&lt;p&gt;We will use a Keystore JSON file (a password-encrypted file). If you use tools like Ape or Foundry, you already have them; &lt;a href="https://x.com/rabuawad_/status/2036067875379663063" rel="noopener noreferrer"&gt;if not, make sure to generate one with eth-account.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Deployment Code
&lt;/h3&gt;

&lt;p&gt;Here is the complete script. It is configured for the Arbitrum Mainnet RPC, but you can change it to Sepolia if you prefer to test first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eth_account&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_keystore_account&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Securely loads an account from a keystore file.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account.keystore.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt; Enter your Keystore password: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;encrypted_account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;account_pk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account_pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Define the network (Arbitrum in this case)
&lt;/span&gt;    &lt;span class="c1"&gt;# You can use a provider like Alchemy/Infura if you want
&lt;/span&gt;    &lt;span class="n"&gt;rpc_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://arb1.arbitrum.io/rpc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_network_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rpc_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# 2. Load the account and add it to the boa environment
&lt;/span&gt;        &lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_keystore_account&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deploying contract with account: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 3. Deploy the contract
&lt;/span&gt;        &lt;span class="c1"&gt;# boa.load compiles and sends the deployment transaction
&lt;/span&gt;        &lt;span class="n"&gt;erc20_contract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contracts/ERC20.vy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My Token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# _name
&lt;/span&gt;            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;           &lt;span class="c1"&gt;# _symbol
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Success! Contract deployed at: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;erc20_contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;erc20_contract&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Launching the Token
&lt;/h3&gt;

&lt;p&gt;To execute it, simply run in your terminal: &lt;code&gt;uv run scripts/deploy.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Titanoboa will compile your Vyper code on the fly, sign the transaction with your encrypted account, and send it to the Arbitrum network.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>python</category>
    </item>
    <item>
      <title>Crypto is changing, and that is a good thing... In the long term</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Wed, 07 Oct 2026 23:22:11 +0000</pubDate>
      <link>https://dev.to/rabuawad/crypto-is-changing-and-that-is-a-good-thing-in-the-long-term-35ni</link>
      <guid>https://dev.to/rabuawad/crypto-is-changing-and-that-is-a-good-thing-in-the-long-term-35ni</guid>
      <description>&lt;h3&gt;
  
  
  Hackathons have changed completely.
&lt;/h3&gt;

&lt;p&gt;You are now most likely not competing for money but for the chance to make money in the long run. That is understandable: most hackathons were won by “bounty hunters,” people who did not want to build the product and only wanted a quick cash grab- literal bounty hunters. That hurt hackathons, and chains have realized there are few incentives left for hosting them. Now hackathons are focused on taking your idea (or MVP) to a real product that generates revenue and has users. That is a better approach in the long term because you reward people who are building real solutions and want to build for the long term, instead of people who build only to collect a check and say goodbye.&lt;/p&gt;




&lt;h3&gt;
  
  
  Grants have disappeared.
&lt;/h3&gt;

&lt;p&gt;Most grant programs have disappeared completely, but many of the chains that gave those grants have not stopped making revenue, so the funds are still there. What I imagine is that grants will focus on key tooling (compilers, frameworks, etc.) and on already existing protocols, which makes a lot of sense. Grants were used to bootstrap ideas; how many successful ideas did they bootstrap? A really small number. Now you have to put yourself out there first, and then you can get the money to keep going, which rewards builders in the long term.&lt;/p&gt;




&lt;h3&gt;
  
  
  Blockchains are (finally) becoming just part of the stack, not the unique selling point.
&lt;/h3&gt;

&lt;p&gt;Let me explain: in the early 2020s, protocols were valued at millions (millions!!) just because they were the only ones doing X on Y blockchain. That was misguided. Blockchains should always have been an implementation detail, not the USP. For example, look at something like Polymarket: do people using Polymarket know they are on Polygon? No. Most of them do not even know they are using a blockchain, and that was the end goal all along. The blockchain should just be part of the stack. Users do not care which blockchain you are building on; they care about the product. You (the developer) are the one who should care, but the end user should not. Good examples of this are Hyperliquid, Polymarket, and USDT.&lt;/p&gt;




&lt;h3&gt;
  
  
  Liquidity is going to concentrate.
&lt;/h3&gt;

&lt;p&gt;In the next couple of years, we are going to see a lot of protocols and chains close and wind down. That is a good thing in the long term, but it is going to signal a new age in crypto. Protocols with no purpose or use case are going to become irrelevant, which, if you think about it, is exactly what happens in every industry. For example, I never saw the use case for POAPs. A lot of people seem shaken by the news of them discontinuing the product, but in reality, the product was overvalued.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>Why "create a wallet" is where most people quit crypto</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Wed, 07 Oct 2026 23:00:12 +0000</pubDate>
      <link>https://dev.to/rabuawad/why-create-a-wallet-is-where-most-people-quit-crypto-1ag2</link>
      <guid>https://dev.to/rabuawad/why-create-a-wallet-is-where-most-people-quit-crypto-1ag2</guid>
      <description>&lt;p&gt;Ask a new user to "create an account" and they know what to do. Ask them to "create a wallet" and you've already lost half of them.&lt;/p&gt;

&lt;p&gt;I've worked in Web3 for the last five years as a full-stack and smart contract developer at startups and protocols. I've given talks to both technical and non-technical audiences, and one theme keeps coming up: &lt;strong&gt;Web3 is extremely complicated for 99% of people.&lt;/strong&gt; The trouble starts on the very first screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  An account is not a wallet
&lt;/h3&gt;

&lt;p&gt;Every app people use has accounts. You sign up with your email, you forget your password, you click "reset password," and you're back in. Nobody thinks twice about it.&lt;/p&gt;

&lt;p&gt;A crypto wallet works differently. There's no "forgot password" button. You get a &lt;strong&gt;seed phrase&lt;/strong&gt;, which is 12 or 24 random words that you're told to write on paper and never show anyone. If you lose those words, or the private key behind them, your money is gone. Forever. No support team can get it back.&lt;/p&gt;

&lt;p&gt;For someone who just wants to receive a payment, that's terrifying. It also opens the door to scams: a fake "support agent" asking for your seed phrase is one of the most common ways people get drained.&lt;/p&gt;

&lt;h3&gt;
  
  
  Self-custody is great
&lt;/h3&gt;

&lt;p&gt;Self-custody has real benefits, and people who want it should have it. But making it the &lt;em&gt;entry point&lt;/em&gt; means most people never get past step one. They don't want to manage keys. They want to log in and get to their money.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✨🍉 &lt;strong&gt;Sandia lets you log in with your email. Simple as that.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use it now at: &lt;a href="https://sandiapay.app/" rel="noopener noreferrer"&gt;sandiapay.app&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  About Sandia
&lt;/h2&gt;

&lt;p&gt;Sandia started with a simple question: &lt;strong&gt;what if using Web3 wasn't complicated?&lt;/strong&gt; Log in with your email and get all the good parts of Web3 (stablecoins, yield, tokenized stocks) without the headaches.&lt;/p&gt;

&lt;p&gt;Sandia is live, and every feature is free. It's under active development, so if you find a bug, want a feature, or have a suggestion, I'd love to hear it.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.sandiapay.app/" rel="noopener noreferrer"&gt;sandiapay.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is part of the **What's broken in Web3&lt;/em&gt;* series:*&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Why "create a wallet" is where most people quit crypto&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"So I need ETH to move my USDT?" The gas fee problem&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Oh. That's on Ultraminion Chain." Why crypto payments keep getting lost&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;DeFi shouldn't need three approvals and a scam detector&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>web3</category>
      <category>cryptocurrency</category>
      <category>ethereum</category>
      <category>ux</category>
    </item>
    <item>
      <title>Web3 Security: How to Protect Your Private Key using Python</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Tue, 06 Oct 2026 19:14:15 +0000</pubDate>
      <link>https://dev.to/rabuawad/web3-security-how-to-protect-your-private-key-using-python-5hj</link>
      <guid>https://dev.to/rabuawad/web3-security-how-to-protect-your-private-key-using-python-5hj</guid>
      <description>&lt;p&gt;In Smart Contract development, the most common (and costly) mistake is leaving private keys in plaintext within .env files or directly in the code. If accidentally pushed to GitHub, your funds will disappear in seconds.&lt;/p&gt;

&lt;p&gt;The professional solution is to use a &lt;strong&gt;Keystore JSON&lt;/strong&gt;: an encrypted file that protects your key with a password. This guide explains how to create a Keystore manager using Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;We will use &lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt;, the fastest Python package manager, and the official Ethereum Foundation library.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize the project: &lt;code&gt;uv init keystore_manager&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install dependencies: &lt;code&gt;uv add eth-account&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create the file: &lt;code&gt;touch manager.py&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Code: Keystore Manager
&lt;/h2&gt;

&lt;p&gt;The script prompts for your private key and a password to generate an encrypted file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eth_account&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/*                      KEYSTORE MANAGER                      */&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;private_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; Enter your private key: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; Enter a password: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;password_confirm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Confirm your password: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;password_confirm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; ---ERROR &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Passwords do not match&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="n"&gt;loaded_account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;json_key_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loaded_account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account.keystore.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_key_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; Keystore created successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Security Points
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;getpass&lt;/strong&gt;: Essential for terminal scripts. It prevents your private key or password from appearing in console history or being visible to onlookers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account.encrypt&lt;/strong&gt;: Uses the Ethereum encryption standard. This generates a file that can only be decrypted with the correct password.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.gitignore&lt;/strong&gt;: Even if encrypted, never upload these files to public repositories. Add *.json or your specific keystore filename to your .gitignore.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;To run your manager, execute:&lt;br&gt;
&lt;code&gt;uv run manager.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once the &lt;em&gt;account.keystore.json&lt;/em&gt; file is generated, you can securely use it in your deployment scripts with Titanoboa, Ape, or Foundry.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>Onchain experiments, and why we need them</title>
      <dc:creator>Rafael Abuawad</dc:creator>
      <pubDate>Tue, 06 Oct 2026 15:55:35 +0000</pubDate>
      <link>https://dev.to/rabuawad/onchain-experiments-and-why-we-need-them-21nk</link>
      <guid>https://dev.to/rabuawad/onchain-experiments-and-why-we-need-them-21nk</guid>
      <description>&lt;p&gt;The blockchain industry should never go stale, but something’s off. What used to feel wide open is getting squeezed by prediction markets and memecoins. That can’t be the whole story.&lt;/p&gt;

&lt;p&gt;When I first ran into Web3, CryptoKitties were a thing, NFTs were everywhere, and DeFi was exploding. You could seriously imagine building the next decentralized stablecoin, the next onchain collectible, the next lending protocol, with millions of people actually using the chain.&lt;/p&gt;

&lt;p&gt;Then a lot changed. Thousands of protocols never shipped. Thousands more faded away. And many of the same names that have been here forever seem to have stopped pushing new ideas.&lt;/p&gt;

&lt;p&gt;People stopped caring, but it doesn’t have to stay that way. We can still build a better future for blockchains; we just need new onchain experiences: less speculation, more real use cases, more things that hold up over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developers need a web3-first mindset.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What I mean: build truly permissionless, trustless protocols- protocols anyone can extend and compose on without an API key- a better use of blockchain tech. Onchain experiments need to feel exciting again. We need novel DeFi, new onchain games, etc. And goes without saying, we should also revisit older ideas that faded because of tech limits or market cycles. Bring that energy back.&lt;/p&gt;

&lt;p&gt;Projects like COINS by &lt;a href="https://x.com/z0r0zzz" rel="noopener noreferrer"&gt;@z0r0zzz&lt;/a&gt; are exactly the kind of direction that’s interesting and has real room to grow.&lt;/p&gt;

&lt;p&gt;We should build applications people want to use, applications that use what blockchains are uniquely good at. The old excuse list is shorter now: many technical limitations are gone, and we have the tooling to make UX genuinely smooth.&lt;/p&gt;

&lt;p&gt;How much value have something like ve(3,3) &amp;amp; Solidly added to DeFi? Something like Aave? Something like Uniswap Hooks? We need that... but times ten.&lt;/p&gt;

&lt;p&gt;I’ll go further: we should bring decentralized algorithmic stablecoins back into the conversation; the current landscape still isn’t good enough.&lt;/p&gt;

&lt;p&gt;To be clear: I’m not telling anyone to dump their life savings into a random DeFi protocol coded in a basement with two fever dreams and a chatbot.&lt;/p&gt;

&lt;p&gt;I am saying we should give serious experiments a fair shot, because something real can still come out of them.&lt;/p&gt;

&lt;p&gt;The industry has centered itself on speculation. Crypto can do more, and even where speculation exists, we can still aim for setups that are more decentralized, more trustless, with stronger game theory, and less extractive.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: Make onchain experiments cool again. Build with a web3-first developer mentality. Explore new ideas, and revive old ones worth another look.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>ai</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
