<?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: ZikCards</title>
    <description>The latest articles on DEV Community by ZikCards (@zikcards).</description>
    <link>https://dev.to/zikcards</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%2F4175182%2F07c3f158-113a-42a8-9155-dd14186b5ff8.png</url>
      <title>DEV Community: ZikCards</title>
      <link>https://dev.to/zikcards</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zikcards"/>
    <language>en</language>
    <item>
      <title>Validating a USDT address before you send: TRON checksums vs EVM addresses</title>
      <dc:creator>ZikCards</dc:creator>
      <pubDate>Tue, 20 Oct 2026 20:43:22 +0000</pubDate>
      <link>https://dev.to/zikcards/validating-a-usdt-address-before-you-send-tron-checksums-vs-evm-addresses-1f3a</link>
      <guid>https://dev.to/zikcards/validating-a-usdt-address-before-you-send-tron-checksums-vs-evm-addresses-1f3a</guid>
      <description>&lt;p&gt;Crypto transfers cannot be reversed. If a user pastes the wrong address, or the right address on the wrong network, the money is usually gone. If your app takes a USDT address from a user, a few checks in the form catch most of these mistakes before anything is sent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two very different address formats
&lt;/h2&gt;

&lt;p&gt;USDT exists on several networks, and their addresses look nothing alike:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TRON (TRC-20):&lt;/strong&gt; starts with &lt;code&gt;T&lt;/code&gt;, 34 characters, base58 encoded, with a built-in checksum.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EVM networks (Ethereum, BNB Smart Chain, Polygon):&lt;/strong&gt; start with &lt;code&gt;0x&lt;/code&gt;, followed by 40 hexadecimal characters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That difference is useful: a TRON address can never pass as an EVM address, and the other way round. So the first check is simply "does this address belong to the network the user picked?"&lt;/p&gt;

&lt;h2&gt;
  
  
  TRON: decode and verify the checksum
&lt;/h2&gt;

&lt;p&gt;A TRON address is base58check: decode it and you get 25 bytes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first byte must be &lt;code&gt;0x41&lt;/code&gt;, the TRON mainnet prefix.&lt;/li&gt;
&lt;li&gt;The last 4 bytes are a checksum: the first 4 bytes of SHA-256 applied twice to the first 21 bytes.&lt;/li&gt;
&lt;li&gt;If the checksum does not match, the address has a typo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The checksum is what makes this strong: change one character in a valid TRON address and the check almost always fails. Length and prefix checks alone would miss that.&lt;/p&gt;

&lt;h2&gt;
  
  
  EVM: format first, then the optional checksum
&lt;/h2&gt;

&lt;p&gt;For &lt;code&gt;0x&lt;/code&gt; addresses the minimum check is the format: &lt;code&gt;0x&lt;/code&gt; plus exactly 40 hex characters.&lt;/p&gt;

&lt;p&gt;On top of that, EIP-55 defines a checksum written into the letter case: in a mixed-case address, each letter is upper or lower case depending on the Keccak-256 hash of the lowercase address. So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an all-lowercase or all-uppercase address carries no checksum, and you can only check its format;&lt;/li&gt;
&lt;li&gt;a mixed-case address that fails EIP-55 contains a typo, so reject it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The mistake no validator can catch
&lt;/h2&gt;

&lt;p&gt;Ethereum, BNB Smart Chain and Polygon use the same address format. The same string is valid on all three, and often it is even the same wallet. So no code can tell whether a user meant BNB Smart Chain or Ethereum.&lt;/p&gt;

&lt;p&gt;What helps instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;show the selected network prominently next to the address field;&lt;/li&gt;
&lt;li&gt;ask the user to confirm the network with a checkbox, enforced on the server, not just in the browser;&lt;/li&gt;
&lt;li&gt;store the network with the transaction, so support can see what was chosen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;I built a free checker that does all of the above in the browser: TRON base58 checksum validation, EVM format and EIP-55 checks, and a warning when the address belongs to a different network than the one selected: &lt;a href="https://zikcards.com/tools/usdt-address-checker" rel="noopener noreferrer"&gt;https://zikcards.com/tools/usdt-address-checker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are not sure which network to use in the first place, this short answer compares the fees and speed of each: &lt;a href="https://zikcards.com/faq/which-network-should-i-send-usdt-on" rel="noopener noreferrer"&gt;https://zikcards.com/faq/which-network-should-i-send-usdt-on&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I am the founder of ZikCards, which issues US Visa and Mastercard virtual cards funded with USDT or USDC. The checker is free and needs no sign-up.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>blockchain</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What the first digits of a card number tell you (BIN basics for developers)</title>
      <dc:creator>ZikCards</dc:creator>
      <pubDate>Sat, 10 Oct 2026 11:56:57 +0000</pubDate>
      <link>https://dev.to/zikcards/what-the-first-digits-of-a-card-number-tell-you-bin-basics-for-developers-4g18</link>
      <guid>https://dev.to/zikcards/what-the-first-digits-of-a-card-number-tell-you-bin-basics-for-developers-4g18</guid>
      <description>&lt;p&gt;If you have ever built a checkout form, you have probably shown a Visa or Mastercard logo as the user types. That logo comes from the first few digits of the card number: the &lt;strong&gt;BIN&lt;/strong&gt;, or Bank Identification Number. This post covers what a BIN tells you, how to detect the brand and validate a number in a few lines of JavaScript, and what you are allowed to keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a BIN is
&lt;/h2&gt;

&lt;p&gt;The first 6 to 8 digits of a card number identify the institution that issued it. The standard (ISO/IEC 7812) calls it the IIN, Issuer Identification Number; the payments industry still says BIN. Since 2022, Visa and Mastercard allocate &lt;strong&gt;8-digit BINs&lt;/strong&gt;, so code that assumes exactly 6 digits will slowly get less accurate.&lt;/p&gt;

&lt;p&gt;A BIN lookup can tell you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network&lt;/strong&gt;: Visa, Mastercard, American Express, Discover, JCB, UnionPay&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Issuer&lt;/strong&gt;: the bank or card programme&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Country&lt;/strong&gt; where the card was issued&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt;: credit, debit or prepaid&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level&lt;/strong&gt;: for example classic, gold, business&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What it can't tell you: the cardholder, the balance, or whether a payment will succeed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting the brand
&lt;/h2&gt;

&lt;p&gt;The first digit narrows it down; a few more settle it. The common ranges:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Network&lt;/th&gt;
&lt;th&gt;Starts with&lt;/th&gt;
&lt;th&gt;Length&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Visa&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;16 (also 13, 19)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mastercard&lt;/td&gt;
&lt;td&gt;51–55, 2221–2720&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;American Express&lt;/td&gt;
&lt;td&gt;34, 37&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discover&lt;/td&gt;
&lt;td&gt;6011, 644–649, 65&lt;/td&gt;
&lt;td&gt;16–19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JCB&lt;/td&gt;
&lt;td&gt;3528–3589&lt;/td&gt;
&lt;td&gt;16–19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UnionPay&lt;/td&gt;
&lt;td&gt;62&lt;/td&gt;
&lt;td&gt;16–19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diners Club&lt;/td&gt;
&lt;td&gt;36, 300–305&lt;/td&gt;
&lt;td&gt;14–19&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ranges overlap in places, so check the most specific prefix first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cardBrand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^3&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;47&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;amex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;36|30&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-5&lt;/span&gt;&lt;span class="se"&gt;])&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;diners&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&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="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3528&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;p&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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3589&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jcb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;6011|64&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;4-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;|65&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;discover&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^62/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unionpay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^5&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;1-5&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&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="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2221&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;p&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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;2720&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mastercard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^4/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is enough for a logo. For anything that matters (fraud rules, routing, telling credit from debit), use a BIN database, because the type and country can't be read from the digits alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Catching typos with the Luhn check
&lt;/h2&gt;

&lt;p&gt;The last digit of a card number is a check digit. The Luhn algorithm catches any single mistyped digit and most swapped neighbours, so you can tell the user before the payment provider does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;luhnValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sum&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sum&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;luhnValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4242 4242 4242 4242&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true  (a well-known test number)&lt;/span&gt;
&lt;span class="nf"&gt;luhnValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4242 4242 4242 4241&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A number that passes Luhn is only &lt;em&gt;well-formed&lt;/em&gt;. It says nothing about whether the card exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you may store
&lt;/h2&gt;

&lt;p&gt;Under PCI DSS you must never store the CVV, and you shouldn't keep the full card number unless you are set up to protect it. The BIN and the last four digits are the usual "safe" pair for receipts, support and fraud rules. Check the PCI Security Standards Council's current truncation guidance for how many leading digits are allowed now that BINs are 8 digits long.&lt;/p&gt;

&lt;p&gt;If you take payments through a hosted field or iframe (Stripe Elements and similar), the full number never reaches your server at all. That is the simplest way to stay out of most of PCI's scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing without real cards
&lt;/h2&gt;

&lt;p&gt;Payment providers publish test numbers that pass Luhn and trigger specific results (approved, declined, 3D Secure challenge). Use those in development and CI, never a real card.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools if you just need an answer
&lt;/h2&gt;

&lt;p&gt;I work on ZikCards, and we keep a few free tools for exactly these questions. No sign-up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://zikcards.com/tools/bin-lookup" rel="noopener noreferrer"&gt;BIN lookup&lt;/a&gt;: network, issuer, country and type for the first digits&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zikcards.com/tools/card-brand-checker" rel="noopener noreferrer"&gt;Card brand checker&lt;/a&gt;: which network a number belongs to&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zikcards.com/tools/test-card-numbers" rel="noopener noreferrer"&gt;Test card numbers&lt;/a&gt;: sandbox numbers by provider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What's the oddest card-number edge case you've hit in a checkout form?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>payments</category>
      <category>fintech</category>
    </item>
  </channel>
</rss>
