<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://blog.unit410.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.unit410.com/" rel="alternate" type="text/html" /><updated>2025-12-18T11:35:04-05:00</updated><id>https://blog.unit410.com/feed.xml</id><title type="html">Unit 410</title><subtitle>Secure, Institutional &amp; Bleeding-Edge</subtitle><author><name>GitHub User</name><email>your-email@domain.com</email></author><entry><title type="html">Bittensor Claim Checker for Stakers</title><link href="https://blog.unit410.com/bittensor/tao/claim/staking/2025/12/18/bittensor-claim-checker-for-stakers.html" rel="alternate" type="text/html" title="Bittensor Claim Checker for Stakers" /><published>2025-12-18T00:00:00-05:00</published><updated>2025-12-18T00:00:00-05:00</updated><id>https://blog.unit410.com/bittensor/tao/claim/staking/2025/12/18/bittensor-claim-checker-for-stakers</id><content type="html" xml:base="https://blog.unit410.com/bittensor/tao/claim/staking/2025/12/18/bittensor-claim-checker-for-stakers.html"><![CDATA[<p>By <a href="https://www.drewrothstein.com">Drew Rothstein</a>, President</p>

<p>The <code class="language-plaintext highlighter-rouge">bittensor</code> protocol has made several staking changes over time.</p>
<ul>
  <li><a href="https://github.com/opentensor/subtensor/pull/2218">https://github.com/opentensor/subtensor/pull/2218</a>: New <code class="language-plaintext highlighter-rouge">KeepSubnets</code> setting to be specific about which subnets one wants to set to <code class="language-plaintext highlighter-rouge">Keep</code> and which to <code class="language-plaintext highlighter-rouge">Swap</code>.</li>
  <li><a href="https://github.com/opentensor/subtensor/pull/2282">https://github.com/opentensor/subtensor/pull/2282</a>: Default change to <code class="language-plaintext highlighter-rouge">Keep</code> and requiring one to manually change to <code class="language-plaintext highlighter-rouge">Swap</code> if desired (Spec <code class="language-plaintext highlighter-rouge">352</code>).</li>
  <li><a href="https://github.com/opentensor/subtensor/pull/2053">https://github.com/opentensor/subtensor/pull/2053</a>: Manual vs. Auto-sell.</li>
</ul>

<p>As these changes have rolled-out, it has become increasingly important to double-check specific setting(s) to make sure it matches intent. Mainly: are key(s) set to <code class="language-plaintext highlighter-rouge">Keep</code> or <code class="language-plaintext highlighter-rouge">Swap</code> as desired?</p>

<p>In that vein, check out this small site: <a href="https://taokeeporswap.com">https://taokeeporswap.com</a></p>

<p>Input an address and check the most recently published claim type.</p>

<p>This is not meant to be expansive or complex - just a simple tool that the community can try as it desires.</p>

<p>One can already do this today with PolkadotJS or the <code class="language-plaintext highlighter-rouge">btcli</code> of course, but those both require somewhat specialized knowledge.</p>

<hr />

<p>If working on these types of networks and utilities is interesting to you, check out our current open positions <a href="https://unit410.com/jobs">here</a>.</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="bittensor" /><category term="tao" /><category term="claim" /><category term="staking" /><summary type="html"><![CDATA[By Drew Rothstein, President]]></summary></entry><entry><title type="html">Decoding the EVM: How We Index Traces And Logs Without ABIs</title><link href="https://blog.unit410.com/accounting/engineering/ethereum/evm/2025/10/31/decoding-the-evm-how-we-index-traces-and-logs-without-abis.html" rel="alternate" type="text/html" title="Decoding the EVM: How We Index Traces And Logs Without ABIs" /><published>2025-10-31T00:00:00-04:00</published><updated>2025-10-31T00:00:00-04:00</updated><id>https://blog.unit410.com/accounting/engineering/ethereum/evm/2025/10/31/decoding-the-evm-how-we-index-traces-and-logs-without-abis</id><content type="html" xml:base="https://blog.unit410.com/accounting/engineering/ethereum/evm/2025/10/31/decoding-the-evm-how-we-index-traces-and-logs-without-abis.html"><![CDATA[<p><img src="/assets/img/decoding-the-evm.png" alt="Decoding the EVM" title="title: Decoding the EVM" /></p>

<p>By <a href="https://www.linkedin.com/in/joelnordell/">Joel Nordell</a>, Lead Accounting Engineer</p>

<p>At Unit 410, we’re obsessed with building a complete and accurate picture of on-chain accounting activity for our clients. This mission requires us to translate the raw, cryptic data from the Ethereum Virtual Machine (EVM) into a clear accounting narrative. To provide meaningful support, we need to understand the function calls (traces) and events (logs) emitted by smart contracts. The traditional approach to this problem relies on Application Binary Interfaces (ABIs), which are JSON files that describe a contract’s functions and events.</p>

<p>However, in my experience, relying on ABIs introduces a significant bottleneck. They aren’t always available, especially for new or closed-source contracts. Managing a large number of them is a complex task in itself, and an outdated ABI can be worse than no ABI at all. We needed a better way—a system that could decode EVM data universally and at scale.</p>

<p>This post explores how we built a robust and scalable decoding pipeline that does not depend on ABIs. I’ll walk through the basics of EVM data, the specific challenges that led us to this approach, and the innovative solutions we implemented to overcome them.</p>

<h2 id="evm-signatures-101-the-hashing-problem">EVM Signatures 101: The Hashing Problem</h2>

<p>To understand our approach, one first needs to understand how the EVM identifies functions and events. Every function and event in a smart contract has a “signature.” For a function, this is its name and argument types (e.g., <code class="language-plaintext highlighter-rouge">transfer(address,uint256)</code>). For an event, it’s the same pattern (e.g., <code class="language-plaintext highlighter-rouge">Transfer(address,address,uint256)</code>).</p>

<p>This signature text is then hashed using <a href="https://en.wikipedia.org/wiki/SHA-3">Keccak-256</a>. It’s critical to understand that this is a <strong>one-way encoding</strong>; it is computationally impossible to reverse the hash to get the original signature. This is the foundational challenge of ABI-less decoding. Given the correct signature, we can decode the binary data, but how do we find the signature (without using an ABI) when all we have is a hash?</p>

<p><strong>For Events:</strong> The full 32-byte hash is used as the first “topic” (<code class="language-plaintext highlighter-rouge">topic0</code>) of a log. Because the full hash is used, it is effectively unique for all practical purposes. A collision is theoretically possible, but so astronomically unlikely that we can reasonably treat it as a unique identifier.</p>

<p><strong>For Functions:</strong> The process is different, and this is where the main problem arises. The Keccak-256 hash of the function signature is <strong>truncated to just the first 4 bytes</strong>. This 4-byte value is called the “function selector.” Because of this severe truncation, it is not a rare or theoretical problem for different function signatures to have the same selector—it’s a common, practical issue known as a “hash collision.”</p>

<p>This ambiguity is more than a data-parsing nuisance; it’s a security vulnerability. Malicious actors can deliberately craft contracts with function signatures that collide with common, legitimate ones (like <code class="language-plaintext highlighter-rouge">transfer(address,uint256)</code>). Their goal is to trick users and wallets into misinterpreting a malicious transaction as a benign one, a technique often used in phishing and other scams. A robust decoding system <em>must</em> be able to navigate this ambiguity to address these risks by providing a clear and accurate picture of what a transaction is truly doing.</p>

<h2 id="our-solution-a-centralized-signature-database">Our Solution: A Centralized Signature Database</h2>

<p>Since reversing the hashes is impossible, our approach is to build a massive, forward-looking lookup table. The heart of our system is a comprehensive database that maps these hashes back to their human-readable signatures. We work with <a href="https://openchain.xyz">an open-source database</a> that has crowd-sourced millions of function and event signatures from the community. In addition to consulting this database to fill in the gaps whenever we can’t find a signature, we also regularly contribute back by submitting new signatures we discover through our own indexing efforts.</p>

<p>This database acts as our dictionary. When we encounter a function selector or an event topic hash, we query the database to find all known matching signatures. But what happens when multiple signatures produce the same hash? Let’s explore how we handle that in our decoding pipeline.</p>

<h2 id="the-decoding-pipeline-in-action">The Decoding Pipeline in Action</h2>

<p>With our signature database in place, we can now process blocks in real-time. As our indexer ingests each new trace and log, it sends them through the following decoding pipeline.</p>

<h3 id="a-decoding-logs-events-the-straightforward-case">A. Decoding Logs (Events): The Straightforward Case</h3>

<p>For logs, the process is refreshingly straightforward, thanks to the full 32-byte topic hash. We extract the <code class="language-plaintext highlighter-rouge">topic0</code> from the log, query our database, and get a single, unambiguous event signature.</p>

<p>Just as with traces, this signature is the crucial schema we need. It tells us the data types for both the <code class="language-plaintext highlighter-rouge">indexed</code> arguments (which are stored in the log’s other topics) and the <code class="language-plaintext highlighter-rouge">non-indexed</code> arguments (which are packed into the log’s data field). Using the signature as our guide, we can parse all the event’s parameters into a structured, human-readable format.</p>

<pre><code class="language-pseudocode">-- Simplified pseudo-code for our log decoding logic

FUNCTION DecodeLog(log):
  -- For logs, the topic hash is unique, so we expect only one signature
  IF log.signature is null THEN:
    RETURN error "No signature found for this log"
  END IF

  -- Decode the log's data and topics using the signature as a schema
  decoded_arguments, error = DecodeEvent(log.data, log.topics, log.signature)

  IF error is not null THEN:
    RETURN error "Failed to decode log"
  END IF

  RETURN decoded_arguments
END FUNCTION
</code></pre>

<h3 id="b-decoding-traces-function-calls-the-real-challenge">B. Decoding Traces (Function Calls): The Real Challenge</h3>

<p>When our indexer processes a trace (a function call), the first step is to extract the 4-byte selector from the <code class="language-plaintext highlighter-rouge">calldata</code>.</p>

<p>Because of the truncation-caused collisions, this selector is not a unique identifier. A query to our database for that selector might return multiple candidate signatures. So, why do we need the signature text?</p>

<p>This is the most important part of the process: the signature string, like <code class="language-plaintext highlighter-rouge">transfer(address,uint256)</code>, is the essential <strong>“schema”</strong> or <strong>“guide”</strong> we need to parse the rest of the calldata. Without this guide, the calldata is just an opaque, meaningless blob of bytes. The signature tells us the exact data types (<code class="language-plaintext highlighter-rouge">address</code>, <code class="language-plaintext highlighter-rouge">uint256</code>) and the order of the arguments packed into that binary data.</p>

<p>Our resolution process is a multi-stage filter designed to find the single best match. We treat each candidate signature as a potential schema and attempt to parse the calldata.</p>

<p>First, we apply a <strong>“strict mode”</strong> check. A signature might successfully decode its required arguments but leave a trail of unused, extraneous bytes at the end of the calldata. This is a “sloppy” match. To prevent this, our strict mode performs a clever test: after a successful decode, it tries to decode the calldata <em>again</em> with the last few bytes truncated. If this second, shorter version also decodes successfully, it proves the original data had extra bytes. We discard these sloppy matches, as they don’t perfectly account for the entire calldata.</p>

<p>After filtering for only the most precise matches with strict mode, what if we <em>still</em> have multiple candidates? This is where our second layer of defense comes in: <strong>prioritization</strong>. We don’t treat all signatures equally. If multiple high-priority signatures still match, our system flags the transaction for human review to help ensure the highest level of accuracy.</p>

<p>This two-step process of strict validation followed by prioritization allows us to resolve collisions with a reasonably high degree of accuracy.</p>

<pre><code class="language-pseudocode">-- Simplified pseudo-code for DecodeCalldata, showing the strict mode check

FUNCTION DecodeCalldata(input_data, signature, strict_mode):
  -- First, try to decode the arguments from the input data
  decoded_arguments, error = UnpackArguments(input_data, signature)

  IF error is not null THEN:
    -- The data doesn't match the signature at all
    RETURN error
  END IF

  -- If we're in strict mode, we perform an extra check
  IF strict_mode is true THEN:
    -- Remove the last few bytes from the input data
    truncated_input = remove_last_bytes(input_data)

    -- Try to decode AGAIN with the truncated data.
    -- We call it non-strictly this time, as we only care if it succeeds at all.
    _, error = DecodeCalldata(truncated_input, signature, false)

    IF error is null THEN:
      -- If the SHORTER version also decodes, it means the original
      -- input had extra, unused data. This is a "sloppy" match.
      RETURN error "Strict mode failure: input data has extraneous bytes"
    END IF
  END IF

  -- If we get here, the decode was successful and passed the strict check
  RETURN decoded_arguments, null
END FUNCTION
</code></pre>

<pre><code class="language-pseudocode">-- Simplified pseudo-code for our trace decoding logic

FUNCTION DecodeTrace(trace):
  -- If we have multiple candidates, we must use strict mode
  use_strict_mode = (length of trace.signatures &gt; 1)

  successful_decodes = []

  FOR EACH signature IN trace.signatures:
    -- Try to decode the trace's input data using the current signature
    decoded_arguments, error = DecodeCalldata(trace.input, signature, use_strict_mode)

    IF error is null THEN:
      -- If successful, add the result to our list of candidates
      result = new DecodeResult(signature, signature.priority, decoded_arguments)
      add result to successful_decodes
    END IF
  END FOR

  IF successful_decodes is empty THEN:
    RETURN error "Could not decode trace with any signature"
  END IF

  -- From our list of successful candidates, find the one with the highest priority
  best_match = FindHighestPriority(successful_decodes)

  RETURN best_match.arguments
END FUNCTION
</code></pre>

<h2 id="innovative-solutions-for-complex-cases-safe-wallet--proxies">Innovative Solutions for Complex Cases: Safe Wallet &amp; Proxies</h2>

<p>The power of this ABI-less approach is most apparent when dealing with the complexities of modern smart contracts, particularly proxy patterns. A great example is the <a href="https://safe.global/">Safe Wallet</a>, a popular multi-signature wallet.</p>

<p>When a user interacts with a Safe, the top-level trace isn’t the true function call (e.g., a <code class="language-plaintext highlighter-rouge">transfer</code>), but rather a call to the Safe’s own <code class="language-plaintext highlighter-rouge">execTransaction</code> function. To a naive indexer, the real transaction is hidden inside the calldata of this outer function.</p>

<p>Our pipeline handles this recursively. When we successfully decode a call as <code class="language-plaintext highlighter-rouge">execTransaction</code>, we don’t stop there. We extract the internal transaction data from its arguments and feed that data right back into the start of the decoding pipeline. This allows us to unwrap the proxy call and decode the true underlying function, providing a high degree of confidence that a complete and accurate picture of the on-chain activity is captured.</p>

<h2 id="why-go-abi-less-the-advantages">Why Go ABI-less? The Advantages.</h2>

<p>Building this system was a significant effort, but it provides powerful advantages:</p>

<ul>
  <li><strong>Universality:</strong> We can decode data from virtually any smart contract, whether it’s newly deployed, closed-source, or a complex proxy. As long as we can determine the correct signature, we don’t need to wait for an ABI.</li>
  <li><strong>Scalability:</strong> The signature database is highly optimized, which promotes the ability to perform this decoding in real-time at a massive scale.</li>
  <li><strong>Resilience:</strong> The system is self-contained. We are not dependent on external ABI sources, which can be a single point of failure.</li>
</ul>

<h2 id="conclusion">Conclusion</h2>

<p>Transforming opaque blockchain data into meaningful, structured information is a fascinating challenge. By moving away from a dependency on ABIs and instead tackling the decoding problem head-on with a comprehensive signature database, we’ve built a system that is more scalable, resilient, and complete than traditional approaches. It’s a journey from an opaque blob of bytes to meaningful, structured information, and it’s this kind of deep data work that allows us to provide industry-leading on-chain accounting data.</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="accounting" /><category term="engineering" /><category term="ethereum" /><category term="evm" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Berachain Operators - Stay Frosty with ValRewardAllocator ❄️</title><link href="https://blog.unit410.com/berachain/valrewardallocator/2025/10/09/berachain-operators-stay-frosty-with-valrewardallocator.html" rel="alternate" type="text/html" title="Berachain Operators - Stay Frosty with ValRewardAllocator ❄️" /><published>2025-10-09T00:00:00-04:00</published><updated>2025-10-09T00:00:00-04:00</updated><id>https://blog.unit410.com/berachain/valrewardallocator/2025/10/09/berachain-operators-stay-frosty-with-valrewardallocator</id><content type="html" xml:base="https://blog.unit410.com/berachain/valrewardallocator/2025/10/09/berachain-operators-stay-frosty-with-valrewardallocator.html"><![CDATA[<p>By <a href="https://www.linkedin.com/in/james-lofgren/">James Lofgren</a>, Protocol Specialist</p>

<p>In blockchain validation, security is paramount. Berachain’s Proof-of-Liquidity consensus relies on validators actively directing protocol rewards, but managing these rewards previously required frequent use of the operator key, increasing the risk of costly compromises. In <a href="https://docs.berachain.com/learn/changelog#august-2025">August 2025</a>, Berachain introduced the <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role, allowing validators to delegate reward allocation tasks to a separate key while keeping the primary operator key offline. This update, detailed in <a href="https://github.com/berachain/BRIPs/blob/main/meta/BRIP-0004.md#cutting-board-operator-separation">BRIP-0004</a>, marks a significant step toward more secure validator operations.</p>

<h2 id="what-changed-secure-delegation-for-reward-management">What Changed: Secure Delegation for Reward Management</h2>

<p>The <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role separates the responsibility of managing BGT (Berachain Governance Token) allocations from the operator key. Previously, validators had to use their operator key for every adjustment to the Cutting Board mechanism. Now, a designated address can handle these updates, authorized by the operator but executed independently.</p>

<p>This new functionality is implemented in the BeraChef contract, which governs reward distribution <a href="https://berascan.com/address/0x4fad86f3ef82478db6cdbe70c43e8dd38390dcac#code#F1#L325">0x4fad86f3ef82478db6cdbe70c43e8dd38390dcac</a>. The key function is:</p>

<pre><code class="language-solidity">function setValRewardAllocator(
    bytes calldata valPubkey,
    address rewardAllocator
)
    external
    onlyOperator(valPubkey)
{
    if (rewardAllocator == address(0)) {
        ZeroAddress.selector.revertWith();
    }
    valRewardAllocator[valPubkey] = rewardAllocator;
    emit ValRewardAllocatorSet(valPubkey, rewardAllocator);
}
</code></pre>

<p>This <code class="language-plaintext highlighter-rouge">setValRewardAllocator</code> function allows the operator to assign a reward allocator for a validator’s public key, protected by the <code class="language-plaintext highlighter-rouge">onlyOperator</code> modifier. Once set, the allocator manages reward adjustments without further operator key interaction.</p>

<h2 id="why-this-matters-mitigating-critical-risks">Why This Matters: Mitigating Critical Risks</h2>

<p>In Berachain, the operator key controls critical validator functions, but prior to the <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role adjusting BGT allocations required signing with the operator key, increasing exposure risks. A compromised operator key could allow an attacker to:</p>

<ul>
  <li>Replace the operator key with one under their control.</li>
  <li>Divert incentive rewards.</li>
  <li>Modify validator commission rates.</li>
  <li>Prevent recovery, as only the active operator key can authorize a replacement, forcing validators to exit entirely to regain control.</li>
</ul>

<p>These vulnerabilities could result in digital asset losses and reputational damage. The <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role addresses this by delegating reward allocation tasks to a separate key, significantly reducing the operator key’s exposure to potential risks.</p>

<h2 id="current-operator-key-management-practices">Current Operator Key Management Practices</h2>

<p>Without the ability to delegate the allocation function, operators had to balance efficiency with risk tolerance. This trade-off is evident in current practices, as shown by this <a href="https://dune.com/j_lo/berachain-operator-reward-allocations">Dune dashboard</a> which provides insight into how different validators approach operator key management. The overwhelming majority of reward allocations appear to be validators with <code class="language-plaintext highlighter-rouge">hot</code> keys—private keys connected to the internet—running on scheduled services or cloud platforms, making them more vulnerable to attacks. Currently, 5 operator keys make up over 80% of daily reward allocation calls, with some exceeding 50 calls per day.</p>

<p><img src="/assets/img/2025-10-09-berachain/berachef-reward-allocations-by-operator.png" alt="Berachef Reward Allocations by Operator" /></p>

<p>Looking deeper at the data, it appears two primary approaches exist:</p>

<ol>
  <li>
    <p><strong>Externally Owned Account (1:1)</strong>: A single externally owned account (EOA) is tied to one validator public key. In a few observed cases, the operator key appears to be <code class="language-plaintext highlighter-rouge">hot</code> based on the frequency of reward allocation transactions. These setups often include recurring transfers of incentive rewards to secure assets, but the operator key remains online, increasing risk.</p>
  </li>
  <li>
    <p><strong>Smart Contract Operator (1: Many)</strong>: Custom setups, such as Infrared, manage multiple validators by setting the operator address to a <a href="https://berascan.com/address/0xb71b3DaEA39012Fb0f2B14D2a9C86da9292fC126">proxy contract</a>. This contract enables a permissioned hot key to be set (<code class="language-plaintext highlighter-rouge">0x3e08c3728a69ab3804af74f55f500ceedb342ac7</code>) which is the only key that can call the <code class="language-plaintext highlighter-rouge">QueueNewCuttingBoard</code> function on the Infrared contract. The Infrared contract, which is set as the operator on multiple validators, then makes this call to the Berachef contract. This setup streamlines validator management, enforces strict access controls, and enables recovery if the hot key is compromised, while also supporting recurring asset sweeps. The <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role now offers this functionality natively, eliminating the need for custom contract development.</p>
  </li>
</ol>

<p><img src="/assets/img/2025-10-09-berachain/berachef-reward-allocations-by-pubkey.png" alt="Berachef Reward Allocations by PubKey" /></p>

<h2 id="the-opportunity-security-and-efficiency">The Opportunity: Security and Efficiency</h2>

<p>The prevalence of operator hot keys underscores the need for safer practices. The <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role presents a transformative opportunity for Berachain validators to enhance both security and efficiency. By delegating BGT allocation tasks to a separate key, validators can keep their operator key in secure cold storage, significantly reducing the risk of compromise while meeting the operational demands of frequent reward adjustments. With this update, validators can now adopt more secure practices without sacrificing efficiency, leveraging Berachain’s infrastructure to protect their assets and reputation.</p>

<h2 id="adoption-status-were-early">Adoption Status: We’re Early</h2>

<p>The <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role, quietly introduced in August 2025, offers significant potential for enhancing validator security and efficiency, yet it remains untapped as validators take time to plan and implement this new feature. A <a href="https://dune.com/queries/5839606">Dune query</a> tracking <code class="language-plaintext highlighter-rouge">ValRewardsAllocatorSet</code> events shows no transactions since launch as of this writing. This presents an opportunity for Berachain validators using hot keys to adopt more secure and efficient practices with this tool.</p>

<h2 id="future-integrations-enabling-strategic-flexibility">Future Integrations: Enabling Strategic Flexibility</h2>

<p>Not only does the <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role improve security, it also provides the foundation for future improvements such as <a href="https://github.com/berachain/BRIPs/blob/main/meta/BRIP-0005.md">BRIP-0005</a>, which will utilize the <code class="language-plaintext highlighter-rouge">ValRewardAllocator</code> role to enable automated reward allocation strategies. Together, these tools allow validators to optimize allocations for delegates, enhancing efficiency without compromising on security.</p>

<p>As Berachain continues to make protocol improvements, adoption of these features is expected to grow. Validators should audit their key management practices, prioritize cold storage, and leverage delegation to minimize risks. The infrastructure is in place for validators to be more secure and efficient—now is the time!</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="berachain" /><category term="valrewardallocator" /><summary type="html"><![CDATA[How Berachain's ValRewardAllocator role enables validators to delegate reward allocation tasks to separate keys, keeping operator keys secure in cold storage while maintaining operational efficiency.]]></summary></entry><entry><title type="html">Stablecoins 2025 - A Maturing Crossing Point between Crypto and Conventional Finance</title><link href="https://blog.unit410.com/stablecoins/tradfi/2025/09/29/stablecoins-2025.html" rel="alternate" type="text/html" title="Stablecoins 2025 - A Maturing Crossing Point between Crypto and Conventional Finance" /><published>2025-09-29T00:00:00-04:00</published><updated>2025-09-29T00:00:00-04:00</updated><id>https://blog.unit410.com/stablecoins/tradfi/2025/09/29/stablecoins-2025</id><content type="html" xml:base="https://blog.unit410.com/stablecoins/tradfi/2025/09/29/stablecoins-2025.html"><![CDATA[<p>By <a href="https://www.linkedin.com/in/christopher-pereira-2589a416/">Chris Pereira</a>, Protocol Specialist</p>

<p>With the halfway point of 2025 past, stablecoins have become one of the most consistent and rapidly expanding segments of the crypto world. These cryptocurrencies, whose stability is designed to be maintained by aligning their values with the values of fiat currencies like the U.S. dollar, have grown from being niche trader tools to essential infrastructure for cross-border payments, remittances, and more. Even after falling from a mid-year high of <a href="https://defillama.com/stablecoins">$290 billion</a> to $230 billion today, the combined market capitalization still represents roughly <a href="https://www.weforum.org/stories/2025/03/stablecoins-cryptocurrency-on-rise-financial-systems/">7% of the entire crypto market</a>. The increase is fueled by record-high volumes of transactions, which for 2024 hit $5.7 trillion and increased by <a href="https://insights.flagshipadvisorypartners.com/2025-is-the-year-of-stablecoins-with-record-volumes-and-ma-momentum">66% alone</a> during the first quarter of 2025. Dominant players like Tether’s USDT, with a market cap of over <a href="https://coinmarketcap.com/currencies/tether/">$150 billion</a>, continue to lead, but the landscape is growing more diversified. Nearly 240 stablecoins have been launched and new entrants are launching all the time, such as  Hype’s USDH, whose bid was recently won by <a href="https://www.theblock.co/post/372128/hyperliquids-home-grown-stablecoin-usdh-goes-live-after-native-markets-winning-bid">Native Markets</a> to bring its HypeEVM stablecoin to market. With the substantial growth in stablecoins, both in projects and market value, TradFi has begun to take notice since it provides substantial revenue opportunity.</p>

<h2 id="recent-and-future-launches-innovation-speeds-up">Recent and Future Launches: Innovation Speeds Up</h2>

<p>The world of stablecoins has seen a plethora of activity in 2024 and 2025, fueled by anticipated and increasing regulatory clarity, technological advancements, and the quest for local solutions. Among the recent highlights is Wyoming’s Frontier Stable Token (FRNT), which became live on mainnet in August 2025. The nation’s first state-backed stablecoin, FRNT aims to provide a government-backed digital dollar for streamlined public sector transactions, a milestone move in fintech adoption to the level of the government.</p>

<p>At the country level, South Korea’s BDACS just introduced KRW1, the country’s first stablecoin pegged to the Won, on the Avalanche blockchain . This move is to address domestic demand for a stable, fiat-collateralized asset in the face of rising crypto adoption across Asia. Looking a bit further back, Paxos introduced its Global Dollar (USDG) in November 2024 through its Singapore branch, introducing yield-paying stablecoin options for international users.</p>

<p>Subsequent launches are set to introduce even more momentum. Tether, maker of the world’s largest stablecoin, <a href="https://tether.io/news/tether-unveils-usat-its-planned-u-s-regulated-dollar-backed-stablecoin-and-will-appoint-bo-hines-as-ceo-of-tether-usat/">stated on September 12, 2025</a>, that it would introduce USA₮ (USAT), a U.S.-regulated dollar-backed stablecoin for American citizens. Teaming with Cantor Fitzgerald and Anchorage Digital Bank, Tether has appointed former congressional candidate <a href="https://www.cnbc.com/2025/09/12/tether-reveals-new-stablecoin-appoints-bo-hines-to-lead-us-business-.html">Bo Hines as CEO</a> of the project, a sign that the company is strategically increasing compliance and eyeing towards U.S. expansion. Meanwhile, Plasma, a blockchain tailored for stablecoins, will launch its mainnet beta in late <a href="https://www.hkma.gov.hk/eng/news-and-media/press-releases/2025/07/20250729-4/">September 2025</a>, possibly opening the door to quicker, cheaper issuance and transfers for issuers globally.</p>

<p>Among other forthcoming releases is <a href="https://metamask.io/news/introducing-metamask-usd-your-dollar-your-wallet">MetaMask’s MetaMask USD</a>, which is set to be launched later in 2025 on Ethereum and Linea networks and is planned to be easily integrated into tens of millions of crypto wallets belonging to an array users. Fiserv is also gearing up its FIUSD stablecoin over the coming months, leveraging its vast infrastructure to bridge off-chain banking with onchain finance. In Hong Kong, a new system of stablecoin licensure enters effect later this year, with issuers <a href="https://www.hkma.gov.hk/eng/news-and-media/press-releases/2025/07/20250729-4/">having until</a> October 31, 2025 to file an application paving the way for regulated Asian stablecoins that may rival the existing largest.</p>

<p>These trends suggest more emphasis on more regulated jurisdictional stablecoins, which increases the viability of onshore options and appeal to institutional players concerned about volatility of emerging market currencies.</p>

<h2 id="deepening-involvement-of-traditional-finance">Deepening Involvement of Traditional Finance</h2>

<p>What was once seen as a crypto fad is now a strategic priority for banks and established financial institutions. The U.S. GENIUS Act of 2025, which gave explicit regulatory guidance on payment stablecoins, accelerated this trend by encouraging TradFi adoption and stablecoin mainstreaming in finance. Notably, the CFTC’s September 2025 initiative to integrate stablecoins as tokenized collateral in derivatives markets, dubbed the “killer app” by Acting Chairman Caroline Pham, further signals <a href="https://www.cftc.gov/PressRoom/PressReleases/9130-25">regulatory support</a> for their role in modernizing financial infrastructure. Banks are no longer sitting around and merely observing; they are now issuing actively, investing, and cooperating.</p>

<p>Bigger players like JPMorgan are writing in-depth <a href="https://www.jpmorgan.com/insights/global-research/currencies/stablecoins">reports</a> on the benefits of stablecoins for cross-border payments, emphasizing their speed and efficiency compared to wires. This illustrates the shifting  landscape alone as they previously spoke out against crypto in the past. Fiserv’s plan to roll out FIUSD shows how payment processors are folding stablecoins into their central business, possibly handling trillions in volume annually. Even states like Wyoming are piloting <a href="https://content.govdelivery.com/accounts/WYGOV/bulletins/3ee734a">sovereign stablecoins</a>, growing synergies between public finance and blockchain.</p>

<p>Institutional investment in stablecoin infrastructure has gone into overdrive, with corporate funding rounds for these startups piling up in 2025 while the long standing companies have started to IPO. The IMF and Bank for International Settlements (BIS) already look into stablecoins’ place in the future <a href="https://www.bis.org/publ/arpdf/ar2025e3.htm">monetary system</a>, mentioning their use to complement CBDCs while introducing private-sector innovation. <a href="https://www.mckinsey.com/industries/financial-services/our-insights/the-stable-door-opens-how-tokenized-cash-enables-next-gen-payments">McKinsey</a> sees 2025 as a critical year, with tokenized cash driving a global realignment of the world’s payments infrastructure. This intervention is not without its challenges; banks need to navigate regulatory barriers and prevent stablecoins from eating into deposit bases.</p>

<h2 id="what-this-means-for-the-future-of-finance">What This Means for the Future of Finance</h2>

<p>The intersection of stablecoins and TradFi has the potential to fundamentally redefine how money flows, maintains value, and mediates exchange. Stablecoins enable fast, low-cost cross-border transactions, addressing traditional banking’s multi-day settlements and potentially saving billions in fees yearly. With wider adoption, they could underpin the U.S. dollar’s supremacy in a digital era, with over <a href="https://www.imf.org/-/media/Files/Publications/Fandd/Article/2025/09/fd-september-2025.ashx">90% of stablecoins anchored to USD</a>, continuing American economic influence to all corners of the globe without employing physical currencies.</p>

<p>Stablecoins could democratize access to finance, particularly in developing markets where remittances over platforms like <a href="https://ripple.com/insights/stablecoin-remittances-efficiency-cost-and-other-benefits/">Ripple</a> or Solana already outpace Western Union, while interoperability with traditional finance may strengthen systemic stability through regulated issuers under frameworks like the GENIUS Act. <a href="https://privatebank.barclays.com/insights/stablecoins-the-new-generation-of-financial-infrastructure-07-2025/">Barclays</a> has described stablecoins as the “new generation of financial infrastructure,” enabling use cases from tokenized securities to micropayments, but the key question is whether crypto-native networks will lead this transformation or whether incumbents such as MoneyGram will integrate stablecoins into their existing services through partnerships with chains like Stellar.</p>

<p>Challenges lie ahead: cross-jurisdictional regulatory fragmentation has the potential to hinder interoperability and de-pegging risks underscore the need for reasonable regulation. Stablecoins can aggravate financial vulnerabilities if poorly managed, though, so calls for FDIC-style insurance or central bank guarantees may grow. Ultimately, 2025’s momentum ensures that stablecoins won’t just sit alongside traditional finance but they’ll reinvent it, as blockchain ease of use meets institutional trust to form a hybrid system.</p>

<p>Are stablecoins the future of money?</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="stablecoins" /><category term="tradfi" /><summary type="html"><![CDATA[How stablecoins became the $230B bridge between crypto and traditional finance in 2025, with transaction volumes up 66% and growing institutional adoption.]]></summary></entry><entry><title type="html">NPM Package Hacks - Hardened Cold Storage Is A Solution</title><link href="https://blog.unit410.com/security/cold%20storage/2025/09/10/npm-package-hacks-hardened-cold-storage-is-a-solution.html" rel="alternate" type="text/html" title="NPM Package Hacks - Hardened Cold Storage Is A Solution" /><published>2025-09-10T00:00:00-04:00</published><updated>2025-09-10T00:00:00-04:00</updated><id>https://blog.unit410.com/security/cold%20storage/2025/09/10/npm-package-hacks-hardened-cold-storage-is-a-solution</id><content type="html" xml:base="https://blog.unit410.com/security/cold%20storage/2025/09/10/npm-package-hacks-hardened-cold-storage-is-a-solution.html"><![CDATA[<p>By <a href="https://www.linkedin.com/in/reinhartmichael/">Mike Reinhart</a>, Head of Network Research</p>

<h2 id="tldr">TL;DR</h2>
<ul>
  <li>A recent phishing attack caused many NPM (Node Package Manager) packages to be compromised with malicious code targeting crypto users.</li>
  <li>Fortunately, it appears that a large-scale theft of digital assets did not occur.</li>
  <li>Given the nature of the attack, however, it serves as an important reminder for crypto users to take security seriously and utilize extra precautions for protecting digital assets.</li>
</ul>

<h2 id="what-happened">What Happened?</h2>
<p>On September 8, 2025, <a href="https://jdstaerk.substack.com/p/we-just-found-malicious-code-in-the">reports</a> of a NPM package developer being compromised began circulating. This was quickly picked up in crypto circles, as the attacker misused the developer’s account to publish malicious versions of popular NPM packages, which in turn could then be used to steal digital assets.</p>

<p>Specifically, the NPM packages believed to be compromised include <em>chalk</em>, <em>strip-ansi</em>, <em>color-convert</em>, <em>color-name</em>, <em>is-core-module</em>, <em>error-ex</em>, <em>simple-swizzle</em>, and <em>has-ansi</em>. A growing list has been assembled <a href="https://socket.dev/blog/npm-author-qix-compromised-in-major-supply-chain-attack">here</a>.</p>

<p>Notably, none of these packages have a crypto focus, and, reportedly, the codebases for individual projects were not directly targeted. Instead, the wide usage of these packages means they are highly likely to be used by some digital asset holders (e.g. as dependencies on often-used websites) and, as a result, might be used to trick them into signing a malicious transaction.</p>

<p>Fortunately, this attack seemingly did not result in a large amount of stolen digital assets.</p>

<h2 id="whats-the-nature-of-the-attack-how-did-it-work">What’s the nature of the attack? How did it work?</h2>
<p>There are a few mechanisms that appear to be at play in this attack. At a high level, a malicious package could be used to inject new code into someone’s web browser, which changes the webpage and its behavior to trick the user.</p>

<p>The first attack vector is to quietly change crypto addresses on a webpage to the attacker’s. Then, the malicious code listens to requests made by the webpage; checks if an Ethereum, Solana, Tron, Litecoin, or Bitcoin Cash address is present; and, if so, swaps in a malicious address that is most similar to the intercepted, correct address (<a href="https://gist.github.com/jdstaerk/f845fbc1babad2b2c5af93916dd7e9fb">here’s a list of addresses associated with this attacker</a>). An unsuspecting user could then transfer digital assets to the attacker’s wallet without realizing it.</p>

<p>The second attack vector begins by checking for website components used by browser wallet extensions. If a relevant extension is found, the malicious code waits for the user to create a transfer, intercepts the generated transaction before the user is prompted to sign it, and replaces the recipient of the transfer with an attacker’s address. Unless the user carefully inspects the entire destination address when signing to ensure it matches the intended address, they could accidentally sign the transfer to the malicious wallet. This is likely true even when using a hardware wallet, such as a Ledger.</p>

<h2 id="what-can-i-do">What can I do?</h2>
<p>At this juncture, suggested best practices often include:</p>

<ol>
  <li><strong>Use a hardware wallet</strong>, such as a Ledger device. As noted above, this may not be a silver bullet. But, while browsers and their extensions may be manipulated to show anything, a hardware wallet’s screen cannot be manipulated. You can be confident that you are signing what you see there.</li>
  <li><strong>Verify every character of addresses</strong> before signing. As attacker tradecraft has become more sophisticated, we suggest reviewing the <em>entire</em> address, as an attack may have generated an address with the same starting and ending characters as the intended address.</li>
  <li><strong>Start with a test transaction</strong> before sending digital assets. In each vector used by this NPM attack, a test transfer would likely catch that digital assets didn’t end up where intended, which is a sign that something might not be right.</li>
</ol>

<p>Also, depending on the circumstances, consider reaching out to Unit 410 👇</p>

<h2 id="unit-410-self-custody-wallets-were-not-impacted">Unit 410 self-custody wallets were not impacted</h2>
<p>While many self-custody products rely on web browsers or hot wallets when signing (even within multisigs), Unit 410’s unique, proprietary design for self-custody wallets:</p>

<ol>
  <li>Signs offline (cold) using protected code paths that are carefully curated;</li>
  <li>Moves mission-critical elements outside browsers, where many attack vectors tend to exist; and</li>
  <li>Supports multi-party verification and automated checks helping to ensure the addresses used are known and secure.</li>
</ol>

<p>Beyond that, we take security seriously. For example, in any cases where an external library must be used, we often pin versions so we do not automatically pull updates that might be malicious.</p>

<p>All of the above are big reasons why our clients use Unit 410 to support their self-custody needs, particularly when dealing with high-value positions in bleeding-edge projects.</p>

<h2 id="were-here-to-chat">We’re here to chat</h2>
<p>At Unit 410, security isn’t just a feature - it’s the foundation of everything we build. Our institutional-grade self-custody solutions utilize cryptographically-secured offline storage, helping clients protect their digital assets against sophisticated attack scenarios. Public company, venture capital, and foundation leaders have chosen Unit 410’s security infrastructure to support their high-value self-custody since 2018.</p>

<p>And, if you love security and are interested in contributing to cutting-edge solutions for digital asset wallets and infrastructure, reach out! We are <a href="https://unit410.com/#jobs">hiring</a>!</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="security" /><category term="cold storage" /><summary type="html"><![CDATA[Unit 410's cold storage as a solution to NPM Package Hacks]]></summary></entry><entry><title type="html">Supporting Digital Asset Treasuries at Unit 410</title><link href="https://blog.unit410.com/engineering/security/2025/09/03/supporting-digital-asset-treasuries.html" rel="alternate" type="text/html" title="Supporting Digital Asset Treasuries at Unit 410" /><published>2025-09-03T00:00:00-04:00</published><updated>2025-09-03T00:00:00-04:00</updated><id>https://blog.unit410.com/engineering/security/2025/09/03/supporting-digital-asset-treasuries</id><content type="html" xml:base="https://blog.unit410.com/engineering/security/2025/09/03/supporting-digital-asset-treasuries.html"><![CDATA[<p>By <a href="https://www.linkedin.com/in/drewrothstein/">Drew Rothstein</a>, President</p>

<p>Public company, venture capital, and foundation leaders have chosen Unit 410’s security infrastructure to support their high-value self-custody since 2018. Digital Asset Treasuries (DATs) are a natural extension of this work - corporate treasury operations applied to digital assets.</p>

<p>The security and operational requirements for DATs align directly with what we’ve been building for years: multi-signature architectures, cold storage systems, compliance tooling, and infrastructure that handles institutional scale.</p>

<h2 id="what-makes-our-dat-infrastructure-different">What Makes Our DAT Infrastructure Different</h2>

<p>Digital Asset Treasuries require a fundamentally different approach to digital asset operations than traditional cryptocurrency holdings. They demand institutional-grade security, comprehensive reporting, and seamless integration with existing corporate systems. Our infrastructure is purpose-built around three core pillars:</p>

<h3 id="️-comprehensive-tooling">⚙️ Comprehensive Tooling</h3>

<p><strong>Advanced Infrastructure</strong></p>

<p>Our purpose-built technology stack is designed specifically for public-company-grade digital asset operations. Every component has been architected with scale, security, and reliability in mind.</p>

<p><strong>Key Features:</strong></p>
<ul>
  <li><strong>Multi-signature wallet architecture</strong>: Advanced cryptographic security with configurable signing thresholds and distributed key management</li>
  <li><strong>API-first design</strong>: Complete programmatic access enabling seamless integration with existing treasury and accounting systems</li>
  <li><strong>Custom approval workflows</strong>: Configurable authorization rules and testing environments for operation approval processes</li>
  <li><strong>Participation</strong>: Early staking, governance, and other participatory support with the ability to help capture unique opportunities at launch</li>
</ul>

<p>We’re the original authors of foundational multi-party computation signing technology like <a href="https://gitlab.com/unit410/tendermint-validator">Tendermint Validator</a> for Cosmos, which became the basis for <a href="https://github.com/strangelove-ventures/horcrux">Strangelove’s implementation</a>. This MPC signing infrastructure that secures high-value staked assets today and directly applies to DAT operations.</p>

<h3 id="-cold-storage">🔒 Cold Storage</h3>

<p><strong>Hardened Security</strong></p>

<p>Security isn’t just a feature - it’s the foundation of everything we build. Our institutional-grade self-custody solutions utilize cryptographically secured offline storage, helping clients protect their digital assets against sophisticated attack scenarios.</p>

<p><strong>Security Infrastructure:</strong></p>
<ul>
  <li><strong>Hardware security modules (HSMs)</strong>: Tamper-resistant hardware for cryptographic key generation, cold storage, and sophisticated operations</li>
  <li><strong>Air-gapped infrastructure</strong>: Isolated systems beyond the internet, eliminating entire classes of remote attacks</li>
  <li><strong>Distributed key storage</strong>: Keys distributed across multiple secure locations using advanced secret sharing strategies</li>
  <li><strong>Assurance options</strong>: Built-in flexibility for varying institutional assurance needs</li>
</ul>

<p>Our approach to cold storage goes beyond simple offline key management. We’ve implemented a multi-layered security architecture that includes physical security, cryptographic protection, and operational security measures that lead the industry.</p>

<h3 id="-industry-leading-reporting">📊 Industry-leading Reporting</h3>

<p><strong>Forward-Looking Transparency</strong></p>

<p>DATs require comprehensive audit trails and real-time visibility into all operations. Our reporting infrastructure provides the transparency and compliance capabilities that public companies and other corporate clients demand.</p>

<p><strong>Reporting Capabilities:</strong></p>
<ul>
  <li><strong>Real-time tracking:</strong>: Live visibility into all digital assets and operations across multiple networks and digital asset types</li>
  <li><strong>Annual penetration test reports</strong>: Regular third-party security assessments for continued security posture</li>
  <li><strong>Custom audit trails</strong>: Detailed operation histories with complete provenance tracking for compliance and internal auditing</li>
  <li><strong>External audits</strong>: Support includes working directly with clients’ independent auditors</li>
</ul>

<p>The reporting infrastructure is designed to meet the most stringent compliance requirements while providing the real-time visibility that modern treasury operations demand.</p>

<h2 id="recent-dat-launches">Recent DAT Launches</h2>

<p>The market has seen significant momentum in DAT adoption, with several high-profile launches demonstrating institutional appetite for sophisticated digital asset operational solutions.</p>

<ul>
  <li>BTC ex: <a href="https://www.livebitcoinnews.com/microstrategy-marks-five-years-of-bitcoin-buying-with-18m-purchase/">Microstrategy</a></li>
  <li>ETH ex: <a href="https://decrypt.co/336694/bitmine-ethereum-stash-8-billion-eth-hits-all-time-high">Bitmine</a></li>
  <li>SOL ex: <a href="https://cryptonews.com/news/sol-strategies-tops-1b-delegated-sol-as-7000-wallets-back-its-upcoming-nasdaq-uplisting/">SOL Strategies</a></li>
  <li><a href="https://crypto.news/story-protocol-heritage-distilling-ip-token-2025/">Story Protocol</a></li>
  <li><a href="https://ir.verb.tech/news-events/press-releases/detail/268/verb-technology-company-nasdaq-verb-announces">The Open Network</a></li>
</ul>

<p>These launches suggest a broader trend toward institutional adoption of digital assets as an asset class requiring sophisticated treasury capabilities.</p>

<h2 id="why-this-works-for-us">Why This Works for Us</h2>

<p>DATs map directly to our existing infrastructure. The self-custody wallets we support for validator operations work for treasury operations. The cold storage systems we use to support regulated funds and other institutions work for treasury digital assets. The monitoring and reporting we built for institutional compliance works for treasury operations.</p>

<p>We’re already running this infrastructure across venture capital, public company, and foundations. DATs just formalize the treasury operational layer on top of security infrastructure we’ve been operating for years.</p>

<p>The result is that institutions can run DATs using the high operational and security standards they apply to traditional assets, backed by infrastructure that’s already protecting institutional digital assets at scale.</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="engineering" /><category term="security" /><summary type="html"><![CDATA[Unit 410's comprehensive infrastructure and support for Digital Asset Treasuries (DATs)]]></summary></entry><entry><title type="html">The Ethereum Validator Exit Issue: 20% Abandon Sync Committee Duties</title><link href="https://blog.unit410.com/ethereum/validation/research/2025/08/20/ethereum-validator-exit-sync-committee-issue.html" rel="alternate" type="text/html" title="The Ethereum Validator Exit Issue: 20% Abandon Sync Committee Duties" /><published>2025-08-20T00:00:00-04:00</published><updated>2025-08-20T00:00:00-04:00</updated><id>https://blog.unit410.com/ethereum/validation/research/2025/08/20/ethereum-validator-exit-sync-committee-issue</id><content type="html" xml:base="https://blog.unit410.com/ethereum/validation/research/2025/08/20/ethereum-validator-exit-sync-committee-issue.html"><![CDATA[<p>By <a href="https://www.linkedin.com/in/nick-h-44a66328/">Nick Haskins</a>, Crypto Infrastructure Tech Lead</p>

<p>Ethereum’s transition to Proof of Stake introduced several mechanisms to maintain network security and efficiency. One critical but often overlooked component is the sync committee - a rotating subset of validators responsible for helping light clients stay synchronized with the beacon chain. For validator operators, understanding sync committee mechanics isn’t just academic knowledge; it’s essential for avoiding penalties when planning validator exits.</p>

<p>Details about the <strong>Sync Committee:</strong></p>

<ul>
  <li><strong>Size</strong>: 512 validators per sync committee</li>
  <li><strong>Duration</strong>: Each sync committee serves for exactly 256 epochs (~27.3 hours)</li>
  <li><strong>Selection</strong>: Validators are pseudo-randomly selected based on the RANDAO reveal</li>
  <li><strong>Overlap</strong>: New committees are selected one epoch before the current committee’s term ends</li>
  <li><strong>Duties</strong>: Sign beacon block headers during their assigned period</li>
</ul>

<p>Selection is also deterministic which is quite cool:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_sync_committee_indices</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">epoch</span><span class="p">):</span>
    <span class="n">MAX_RANDOM_BYTE</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="mi">8</span> <span class="o">-</span> <span class="mi">1</span>
    <span class="n">active_validator_indices</span> <span class="o">=</span> <span class="nf">get_active_validator_indices</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">epoch</span><span class="p">)</span>
    <span class="n">active_validator_count</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">active_validator_indices</span><span class="p">)</span>
    <span class="n">seed</span> <span class="o">=</span> <span class="nf">get_seed</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">epoch</span><span class="p">,</span> <span class="n">DOMAIN_SYNC_COMMITTEE</span><span class="p">)</span>

    <span class="n">sync_committee_indices</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">random_byte</span> <span class="o">=</span> <span class="nf">hash</span><span class="p">(</span><span class="n">seed</span> <span class="o">+</span> <span class="nf">uint_to_bytes</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>

    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">SYNC_COMMITTEE_SIZE</span><span class="p">):</span>
        <span class="n">shuffled_index</span> <span class="o">=</span> <span class="nf">compute_shuffled_index</span><span class="p">(</span>
            <span class="n">i</span> <span class="o">%</span> <span class="n">active_validator_count</span><span class="p">,</span>
            <span class="n">active_validator_count</span><span class="p">,</span>
            <span class="n">seed</span>
        <span class="p">)</span>
        <span class="n">candidate_index</span> <span class="o">=</span> <span class="n">active_validator_indices</span><span class="p">[</span><span class="n">shuffled_index</span><span class="p">]</span>

        <span class="k">if</span> <span class="nf">hash</span><span class="p">(</span><span class="n">seed</span> <span class="o">+</span> <span class="nf">uint_to_bytes</span><span class="p">(</span><span class="n">i</span> <span class="o">//</span> <span class="mi">32</span><span class="p">))[</span><span class="n">i</span> <span class="o">%</span> <span class="mi">32</span><span class="p">]</span> <span class="o">*</span> <span class="n">active_validator_count</span> <span class="o">&lt;</span> <span class="n">MAX_RANDOM_BYTE</span><span class="p">:</span>
            <span class="n">sync_committee_indices</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">candidate_index</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">sync_committee_indices</span>
</code></pre></div></div>

<h2 id="validator-exit-process-overview">Validator Exit Process Overview</h2>

<p>When a validator operator decides to exit, they submit a voluntary exit message. However, the exit doesn’t happen immediately:</p>

<ul>
  <li><strong>Exit Epoch</strong>: The earliest epoch when the validator can exit</li>
  <li><strong>Withdrawable Epoch</strong>: When the validator’s balance becomes withdrawable (typically 256 epochs after exit)</li>
  <li><strong>Queue Management</strong>: Exits are rate-limited to maintain network stability</li>
</ul>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-20-ethereum-validator-exit-sync-committee-issue/1.png" alt="Validator Exits Timeline" />
      <span style="text-align: center; font-size: 12px; display: block;">Validator Exits by Epoch (past 2yrs)</span>
    </td>
  </tr>
</table>

<h2 id="the-sync-committee-penalty-research">The Sync Committee Penalty Research</h2>

<p>Timing matters because exiting isn’t instantaneous. Committees are <strong>selected 256 epochs in advance</strong>, so even if a validator submits an exit, they can still be assigned to the next sync committee. The exit itself will process on schedule, but it doesn’t cancel that pending duty — the validator remains in the committee for the rest of the period and is expected to keep signing, with the risk of penalties if they fail to do so.</p>

<p>The following calculation shows how these penalties are applied when a validator misses their sync committee duty, with up to <strong>8,192 individual penalties possible</strong> over the course of a single sync committee period.</p>

<p>Penalty Calculation:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>penalty = base_reward_per_increment * SYNC_REWARD_WEIGHT * (1 - sync_aggregate.sync_committee_bits[index])
</code></pre></div></div>

<p>Where:</p>
<ul>
  <li><strong>base_reward_per_increment</strong>: Base reward scaled by effective balance</li>
  <li><strong>SYNC_REWARD_WEIGHT</strong>: Currently set to 2</li>
  <li>Missing all duties for a full sync committee period can result in penalties of ~0.1-0.2 ETH</li>
</ul>

<p>There’s currently no on-chain protocol that prevents a validator from exiting even if they’ve already been selected for an upcoming sync committee.</p>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-20-ethereum-validator-exit-sync-committee-issue/2.png" alt="Distribution of Miss Rates" />
    </td>
  </tr>
</table>

<p>The distribution shows a clear divide: the overwhelming majority of validators continue fulfilling their duties with very low miss rates, while a smaller subset effectively shuts down, abandoning all responsibilities after exit.</p>

<h2 id="how-often-do-validators-exit-with-pending-sync-committee-responsibilities-and-what-is-the-impact">How often do Validators exit with pending Sync Committee responsibilities? And, what is the impact?</h2>

<p>To understand the actual impact, we developed a Python <a href="https://gist.github.com/nick-u410/fb94ed100630deae967f4454d363619d">script</a> that directly analyzes beacon chain data, scanning for validators that exited in the last 30 days and had pending sync committee responsibilities. The results are striking and provide concrete evidence of a concerning divide.</p>

<h4 id="real-world-analysis-2-year-comprehensive-dataset">Real-World Analysis: 2-Year Comprehensive Dataset</h4>

<p>Using the above script, we analyzed validator exit behavior over a full <strong>2-year period</strong>. The script identified <strong>894 validators</strong> who exited while still holding pending sync committee responsibilities. From our research, this dataset provides the first comprehensive evidence of validator performance post-exit: while most continued to meet their duties, <strong>1 in 5 (19.91%) significantly abandoned responsibilities</strong>, leading to measurable financial penalties and network reliability concerns.</p>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-20-ethereum-validator-exit-sync-committee-issue/3.png" alt="Eth Validator Performance Distribution" />
    </td>
  </tr>
</table>

<h4 id="the-good-news-engaged-majority-716-validators-8009"><strong>The Good News:</strong> Engaged Majority (716 Validators, 80.09%)</h4>

<p>The majority of validators who exited with sync committee duties continued to fulfill their obligations:</p>
<ul>
  <li><strong>4 validators</strong> — Perfect performance (0% miss rate)</li>
  <li><strong>712 validators</strong> — Excellent performance (0.14% – 9.99% miss rate)</li>
  <li><strong>Average miss rate</strong> (well-performing group): ~3.2%</li>
</ul>

<h4 id="the-concerning-reality-disengaged-minority-178-validators-1991"><strong>The Concerning Reality:</strong> Disengaged Minority (178 Validators, 19.91%)</h4>

<p>However, <em>1 in 5 validators</em> did not fulfill their obligations, creating a spectrum of abandonment:</p>
<ul>
  <li><strong>Complete Infrastructure Shutdown</strong> (93 validators)</li>
  <li><strong>Significant Degradation</strong> (85 validators)</li>
</ul>

<p>While 4 out of 5 validators met their obligations, the remaining 19.91% introduced reliability risks for light clients and incurred financial penalties. This suggests a significant education and tooling gap within the validator ecosystem.</p>

<h4 id="financial-impact-the-real-cost-of-the-1991"><strong>Financial Impact</strong>: The Real Cost of the 19.91%</h4>

<p><strong>Total Dataset: 894 Validators with Sync Committee Duties</strong></p>
<ul>
  <li>716 well-performing validators: Minimal penalties (avg ~0.013 ETH each)</li>
  <li>178 abandoning validators: Significant penalties</li>
</ul>

<p><strong>Complete Infrastructure Shutdown:</strong></p>
<ul>
  <li>93 validators with 100% miss rates = ~17.8 ETH total penalties (~$75,000 @ $4,250/ETH)</li>
</ul>

<p><strong>Degraded Performance:</strong></p>
<ul>
  <li>85 validators with varying degrees of missed duties = ~13.6 ETH combined penalties (~$58,000 @ $4,250/ETH)</li>
  <li>Average penalty per degraded validator: ~0.16 ETH (~$680)</li>
</ul>

<p><strong>2-Year Impact from Abandoning Validators:</strong></p>
<ul>
  <li><strong>178 validators</strong> with sync committee issues</li>
  <li><strong>Estimated penalties</strong>: ~31.8 ETH (~$135,200 @ $4,250/ETH)</li>
  <li><strong>Average penalty per abandoning validator</strong>: 0.178 ETH ($756)</li>
  <li><strong>Well-performing validators</strong>: minimal penalties (~$55 average)</li>
</ul>

<p>While the individual financial penalties might seem modest (~$756 per abandoning validator), the 19.91% abandonment rate creates an annual cost of ~$68k across the ecosystem, with more significant implications for network reliability and light client security.</p>

<h3 id="how-validators-can-prevent-this-issue">How Validators Can Prevent This Issue</h3>

<p>The good news is that avoiding penalties and ensuring reliable performance is straightforward if operators take a few extra precautions. The most critical step is <strong>checking whether the relevant validator has pending sync committee duties before shutting down the host/turning off the validating software.</strong></p>

<p>Here’s one method using a Lighthouse archival node that we’ve used:</p>

<p><strong>Check Current Sync Committee</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">VALIDATOR_INDEX</span><span class="o">=</span>1801123
curl <span class="nt">-X</span> GET <span class="s2">"http://localhost:1099/api/v1/validator/</span><span class="nv">$VALIDATOR_INDEX</span><span class="s2">/sync_committee"</span> <span class="se">\</span>
  <span class="nt">-H</span> <span class="s2">"accept: application/json"</span>
</code></pre></div></div>

<p><strong>Check Next Sync Committee</strong></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">VALIDATOR_INDEX</span><span class="o">=</span>1801123
<span class="nv">NEXT_EPOCH</span><span class="o">=</span><span class="k">$((</span> <span class="si">$(</span>curl <span class="nt">-s</span> http://localhost:1099/eth/v1/beacon/headers/head <span class="se">\</span>
                  | jq <span class="nt">-r</span> <span class="s1">'.data.header.message.slot'</span><span class="si">)</span> <span class="o">/</span> <span class="m">32</span> <span class="o">+</span> <span class="m">256</span> <span class="k">))</span>
curl <span class="nt">-s</span> <span class="s2">"http://localhost:1099/eth/v1/beacon/states/head/sync_committees?epoch=</span><span class="nv">$NEXT_EPOCH</span><span class="s2">"</span> <span class="se">\</span>
  | jq <span class="nt">--arg</span> v <span class="s2">"</span><span class="nv">$VALIDATOR_INDEX</span><span class="s2">"</span> <span class="s1">'.data.validators | index($v)'</span>
</code></pre></div></div>

<ul>
  <li><strong>If an integer is returned</strong>, your validator is part of the committee and expected to perform duties.</li>
  <li><strong>If null is returned</strong>, your validator is not scheduled for committee participation.</li>
</ul>

<p><strong>Why this matters</strong>: Even some block explorers (like beaconcha.in) may suggest it’s safe to shut down when in fact your validator still has pending sync responsibilities. This subtle edge case is exactly what leads to penalties and reliability issues.</p>

<p>By running these checks — both for the current and upcoming sync committee — operators should be able to confidently plan exits without unintentionally abandoning duties.</p>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-20-ethereum-validator-exit-sync-committee-issue/4.png" alt="Beaconcha.in says its OK to exit" />
    </td>
  </tr>
</table>

<h2 id="key-takeaways">Key Takeaways</h2>

<p>This extensive analysis of 894 validators over 2 years reveals a clear pattern: while 80.09% of validators maintain excellent sync committee performance after exit, the 19.91% who abandon their duties create an annual cost of $65,000 and weaken network reliability. The stark contrast—with abandoning validators facing 14x higher penalties—suggests this isn’t a technical limitation but an education gap.</p>

<p>The solution is straightforward and already demonstrated by the majority:</p>
<ol>
  <li>Check sync committee status before exit</li>
  <li>Wait for sync committee period completion</li>
  <li>Maintain infrastructure until all duties are fulfilled</li>
</ol>

<p>Based on this analysis, we’ve updated our validator management tools to automatically check sync committee status and provide countdown timers for period completion. With proper tooling and awareness, this entirely preventable issue can be reduced to near zero, strengthening Ethereum’s network while eliminating these unnecessary penalties.</p>

<p>If this type of analysis and work is interesting to you, check out our open roles <a href="https://jobs.ashbyhq.com/unit410?utm_source=pW25OW0YR8">here</a>.</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="ethereum" /><category term="validation" /><category term="research" /><summary type="html"><![CDATA[Analysis of validator behavior when exiting with pending sync committee responsibilities reveals 20% abandon their duties, creating network reliability concerns]]></summary></entry><entry><title type="html">Coworking Weeks at Unit 410</title><link href="https://blog.unit410.com/engineering/team/2025/08/13/coworking-weeks-at-unit-410.html" rel="alternate" type="text/html" title="Coworking Weeks at Unit 410" /><published>2025-08-13T00:00:00-04:00</published><updated>2025-08-13T00:00:00-04:00</updated><id>https://blog.unit410.com/engineering/team/2025/08/13/coworking-weeks-at-unit-410</id><content type="html" xml:base="https://blog.unit410.com/engineering/team/2025/08/13/coworking-weeks-at-unit-410.html"><![CDATA[<p>By <a href="https://www.linkedin.com/in/drewrothstein/">Drew Rothstein</a>, President</p>

<p>Sometimes you just need to be in-person to do your best work.  This is particularly true with cross-team projects and complex re-architectures.</p>

<p>We’ve <a href="https://blog.unit410.com/team/2022/04/14/unit410-how-are-engineering-team-works.html">written</a> about how we work before and that we are a remote company with some locations having centralized teams.  While we do all get together for Offsites multiple times a year (and have some pretty fierce pickleball + basketball games with only minor injuries), these are not focused on heads-down work.</p>

<p>Recently, we had a complex project come up that involved two teams: our Product Engineering team and our Encryption Engineering team.  During initial discussions it was clear that we would be defining a new schema, a new way for the Product to coordinate with a new API, and begin building a completely new UX.</p>

<p>For a project like this, we pondered a few questions:</p>
<ul>
  <li>Did we want to attempt to do this remotely?</li>
  <li>If we did, would the result be enabled as quickly?</li>
  <li>Would the cross-team learning / outcome be as valuable?</li>
  <li>Could we ship a demo by end-of-week if done remotely?</li>
</ul>

<p>It was quickly concluded that the best way to accomplish the highest value outcome was going to be a Coworking Week.</p>

<h2 id="planning-a-coworking-week">Planning a Coworking Week</h2>

<p>We use Slack for team communication and created a dedicated channel + kick-off so that everyone could coordinate.</p>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-13-coworking-weeks/01.slack-channel-kick-off.png" alt="Slack Channel Kick-off" />
      <span style="text-align: center; font-size: 12px; display: block;">Slack Channel Kick-off</span>
    </td>
  </tr>
</table>

<h2 id="choosing-location">Choosing Location</h2>

<p>The first and most important discussion is of course: Where should we all meet?  The team chose Austin, TX where the average temperature was 99°F each day with a 65°F dewpoint.  I can’t say I truly understand this choice but they chose it!</p>

<p>Coordinating the time is the first step with the team selecting a week, confirming availability, and then finding a suitable location.  Key requirement: Fast and secure WiFi.</p>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-13-coworking-weeks/02.choosing-a-week.png" alt="Choosing a week" />
      <span style="text-align: center; font-size: 12px; display: block;">Choosing a week</span>
    </td>
  </tr>
</table>

<p>For an Offsite a hotel is great, everyone gets their own space / privacy but for a Coworking Week it is common for a smaller group to prefer a roomy AirBNB / VRBO with a kitchen and various amenities to make collaboration space / time the most optimized.</p>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-13-coworking-weeks/03.not-the-bnb-we-chose.png" alt="Not the BnB we chose" />
      <span style="text-align: center; font-size: 12px; display: block;">Not the BnB we chose</span>
    </td>
  </tr>
</table>

<h2 id="setting-goals">Setting Goals</h2>

<p>After the location is chosen, the next step is to map out which restaurants… I mean, to plan the goal for the week.  This isn’t a cheap endeavour in dollars or time: we are asking people to step away from their lives, families, et cetera, and spend a week together in another city.</p>

<p>The team spun-up a document and started to outline the <u>Goals</u>, <u>Non-Goals</u>, and specifically: What is actually <u>in-scope</u>?</p>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-13-coworking-weeks/04.setting-goals.png" alt="Setting Goals" />
      <span style="text-align: center; font-size: 12px; display: block;">Setting Goals</span>
    </td>
  </tr>
</table>

<h2 id="go-go-gadget-coworking">Go Go Gadget Coworking</h2>

<p>Once the team lands and acquires their first taco (and maybe a second), the work begins.  Typically supplies are procured such as extension cords, power bricks, and a white board but this varies based-on location.</p>

<p>Work begins on really decomposing the work and fleshing out what is going to be done during the week.  This process takes time, and sometimes an additional taco.  This phase is not rushed nor should it be.  Most work in Engineering is actually non-technical and involves figuring out how you actually want something to work / how it should work, and the outcome(s).</p>

<p>Which team will own which interfaces, where / how is the schema going to be designed, which APIs may be needed / exposed, and what questions are unanswered that we need Product / Other input on?</p>

<p>All of this information is captured and eventually distilled into a shared document.</p>

<p>As the first day ends, a recap post is shared out to the rest of the team.  This is done to keep everyone in the loop (incl. folks that are not physically present) but also to make it clear to the broader team what is being done and the value of the in-person time.</p>

<table>
  <tr>
    <td width="100%">
      <img src="/assets/img/2025-08-13-coworking-weeks/05.day1-recap.png" alt="Day 1 Recap" />
      <span style="text-align: center; font-size: 12px; display: block;">Day 1 Recap</span>
    </td>
  </tr>
</table>

<p>Each day concludes with similar daily updates and photos of IRL activities:</p>

<table>
  <tr>
    <td width="50%">
      <img src="/assets/img/2025-08-13-coworking-weeks/06.day2-recap.png" alt="Day 2 Recap" />
      <span style="text-align: center; font-size: 12px; display: block;">Day 2 Recap</span>
    </td>
    <td width="50%">
      <img src="/assets/img/2025-08-13-coworking-weeks/07.irl-activities.png" alt="IRL Activities, probably Tacos (Blues on the Green)" />
      <span style="text-align: center; font-size: 12px; display: block;">IRL Activities, probably Tacos (<a href="https://www.austintexas.org/listings/blues-on-the-green/2673/">Blues on the Green</a>)</span>
    </td>
  </tr>
</table>

<h2 id="end-of-week">End of Week</h2>

<p>Once the week draws to a close, two final items take place:</p>
<ul>
  <li>A team demo of the work accomplished.</li>
  <li>A more detailed recap of the week.</li>
</ul>

<p>Our team holds a Demo Day every Friday afternoon and Product Demos as part of our Weekly Team Meeting on Mondays.  The team put together a Live Demo (required) and shared the state of what they built / executed on during the past week.  Even if rough and unfinished it is important to demo.</p>

<p>And, a larger recap post was published.</p>

<table>
  <tr>
    <td width="40%">
      <img src="/assets/img/2025-08-13-coworking-weeks/08.top-secret-recap.png" alt="Top secret recap" />
      <span style="text-align: center; font-size: 12px; display: block;">Top secret recap</span>
    </td>
    <td width="60%">
      <img src="/assets/img/2025-08-13-coworking-weeks/09.demo.png" alt="Demo" />
      <span style="text-align: center; font-size: 12px; display: block;">Demo</span>
    </td>
  </tr>
</table>

<h2 id="wrap-up">Wrap-up</h2>

<p>Once everyone completes their journeys back home, the work continues.  The original document that was used to plan, is used to continue the work on the project.  The remaining scope is discussed, planned, and agreed upon for upcoming sprints.  And, the project ships!</p>

<p>We are hiring for a number of roles.  Even if now isn’t the right time, we are happy to keep in touch and let you know when a role that may interest you becomes available.  Check out our roles <a href="https://jobs.ashbyhq.com/unit410?utm_source=AMx1vLRkWJ">here</a>.</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="engineering" /><category term="team" /><summary type="html"><![CDATA[By Drew Rothstein, President]]></summary></entry><entry><title type="html">Qualified Self-Custody Proposal to the SEC Crypto Task Force</title><link href="https://blog.unit410.com/legal/2025/05/07/qualified-self-custody-proposal-to-the-sec-crypto-task-force.html" rel="alternate" type="text/html" title="Qualified Self-Custody Proposal to the SEC Crypto Task Force" /><published>2025-05-07T00:00:00-04:00</published><updated>2025-05-07T00:00:00-04:00</updated><id>https://blog.unit410.com/legal/2025/05/07/qualified-self-custody-proposal-to-the-sec-crypto-task-force</id><content type="html" xml:base="https://blog.unit410.com/legal/2025/05/07/qualified-self-custody-proposal-to-the-sec-crypto-task-force.html"><![CDATA[<p><br /><br /></p>

<p>Read Unit 410's letter to the SEC Crypto Task Force requesting regulatory guidance and proposing a Qualified Self-Custodian (QSC) framework for registered investment advisers (RIAs) to self-custody when secure and reasonable Qualified Custodian (QC) options are not available: <a href="https://www.sec.gov/files/unit-410-050725.pdf">https://www.sec.gov/files/unit-410-050725.pdf</a>.</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="legal" /><summary type="html"><![CDATA[Unit 410's letter to the SEC Crypto Task Force requesting regulatory guidance and proposing a Qualified Self-Custodian (QSC) framework]]></summary></entry><entry><title type="html">Bittensor Validation with Proxy Pallets</title><link href="https://blog.unit410.com/engineering/bittensor/2025/03/06/bittensor-validation-with-proxy-pallets.html" rel="alternate" type="text/html" title="Bittensor Validation with Proxy Pallets" /><published>2025-03-06T00:00:00-05:00</published><updated>2025-03-06T00:00:00-05:00</updated><id>https://blog.unit410.com/engineering/bittensor/2025/03/06/bittensor-validation-with-proxy-pallets</id><content type="html" xml:base="https://blog.unit410.com/engineering/bittensor/2025/03/06/bittensor-validation-with-proxy-pallets.html"><![CDATA[<p>By <a href="https://www.linkedin.com/in/wesleygraham">Wesley Graham</a>, Infrastructure Engineer</p>

<p>At Unit 410, we prioritize security and efficiency for the dozens of networks we support (Bittensor included). Our team operates using advanced infrastructure, secure practices, and custom-built tools as illustrated by our proxy pallet solution.</p>

<h2 id="bittensor-proxy-pallet">Bittensor Proxy Pallet</h2>

<p>In April 2024, proxy pallet support was <a href="https://github.com/opentensor/subtensor/pull/286">added</a> to the Bittensor network. The proxy pallet is a substrate module that allows one account (a “proxy”) to act for another (“proxied”) account with specific permissions. This is useful for cold wallet users seeking to <strong>delegate</strong> execution of certain actions to another key.</p>

<p>Using the proxy pallet, a coldkey can designate a proxy account to perform specific actions for the coldkey. These permissions are (<a href="https://github.com/opentensor/subtensor/blob/5073ade602c367471f5124329b9d7ccf8e972d69/runtime/src/lib.rs#L700">link</a>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Owner
NonCritical
NonTransfer
Senate
NonFungible
Triumvarate
Governance
Staking
Registration
Transfer
SmallTransfer
RootWeights
Childkeys
SudoUncheckedSetCode
</code></pre></div></div>

<h2 id="unit-410-proxy-support">Unit 410 Proxy Support</h2>

<p><img src="/assets/img/2025-03-06-proxy-pallets/proxy-architecture.png" alt="ProxyArchitecture" />
<img src="/assets/img/2025-03-06-proxy-pallets/non-proxy-architecture.png" alt="NonProxyArchitecture" /></p>

<p>A proxy can be utilized in place of frequently utilizing asset-bearing keys for common, low-risk operations like <a href="https://docs.bittensor.com/subnets/child-hotkeys">childkeying to subnets</a>.</p>

<p>In the above model, a user’s coldkey retains full control and ownership, while the proxy only receives CHK-related permissions. If the above proxy key is compromised, asset transfers are programmatically disabled - which cuts off the potential for coldkey asset loss.</p>

<p>The recent <a href="https://www.chainalysis.com/blog/bybit-exchange-hack-february-2025-crypto-security-dprk/">Bybit hack</a> illustrates the importance of transaction preparation and review - and illustrates the unintended consequences that transaction validation errors can lead to. While proxy-type accounts do not solve for this entirely, they do limit the general use of cold, asset-bearing accounts - with necessary spending protections in place to avoid catastrophe in the case of account compromise. In the case of Bybit, if the compromised multisig were a proxy account without spending permissions, attackers would not be able to siphon assets via malicious transaction bytes.</p>

<h2 id="proxy-example">Proxy Example</h2>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Import dependencies</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">ApiPromise</span><span class="p">,</span> <span class="nx">WsProvider</span><span class="p">,</span> <span class="nx">Keyring</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">@polkadot/api</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">cryptoWaitReady</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">@polkadot/util-crypto</span><span class="dl">'</span><span class="p">);</span>

<span class="c1">// Used to represent "max balance" (100% of validator balance) being delegated to a single child key on a subnet.</span>
<span class="kd">const</span> <span class="nx">MAX_U64</span> <span class="o">=</span> <span class="nc">BigInt</span><span class="p">(</span><span class="dl">'</span><span class="s1">18446744073709551615</span><span class="dl">'</span><span class="p">)</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">mnemonic</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">PROXY_ACCOUNT_MNEMONIC</span><span class="p">;</span>
    <span class="kd">const</span> <span class="nx">netuid</span> <span class="o">=</span> <span class="nf">parseInt</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NETUID</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span> <span class="c1">// NetUID from environment</span>
    <span class="kd">const</span> <span class="nx">hotKey</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">HOT_KEY_ADDRESS</span><span class="p">;</span>
    <span class="kd">const</span> <span class="nx">coldKey</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">COLD_KEY_ADDRESS</span><span class="p">;</span>
    <span class="kd">const</span> <span class="nx">childKey</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">CHILD_KEY_ADDRESS</span><span class="p">;</span>
    <span class="kd">const</span> <span class="nx">providerEndpoint</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">PROVIDER_ENDPOINT</span><span class="p">;</span>

    <span class="c1">// Validation: Ensure all required environment variables are provided</span>
    <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">mnemonic</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error: MNEMONIC must be provided as an environment variable.</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if </span><span class="p">(</span><span class="nf">isNaN</span><span class="p">(</span><span class="nx">netuid</span><span class="p">))</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error: NETUID must be provided as a valid number environment variable.</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">hotKey</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error: HOT_KEY must be provided as an environment variable.</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">coldKey</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error: COLD_KEY must be provided as an environment variable.</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">childKey</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error: CHILD_KEY must be provided as an environment variable.</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">providerEndpoint</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error: PROVIDER_ENDPOINT must be provided as an environment variable.</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">// Initialize Polkadot.js and wait for crypto initialization</span>
    <span class="k">await</span> <span class="nf">cryptoWaitReady</span><span class="p">();</span>
    <span class="kd">const</span> <span class="nx">provider</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">WsProvider</span><span class="p">(</span><span class="nx">providerEndpoint</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">api</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">ApiPromise</span><span class="p">.</span><span class="nf">create</span><span class="p">({</span> <span class="nx">provider</span> <span class="p">});</span>

    <span class="c1">// Initialize keyring and accounts</span>
    <span class="kd">const</span> <span class="nx">keyring</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Keyring</span><span class="p">({</span> <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">sr25519</span><span class="dl">'</span> <span class="p">});</span>
    <span class="kd">const</span> <span class="nx">proxy</span> <span class="o">=</span> <span class="nx">keyring</span><span class="p">.</span><span class="nf">addFromUri</span><span class="p">(</span><span class="nx">mnemonic</span><span class="p">);</span> <span class="c1">// Replace with Proxy seed</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`Proxy Address: </span><span class="p">${</span><span class="nx">proxy</span><span class="p">.</span><span class="nx">address</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`ColdKey Address: </span><span class="p">${</span><span class="nx">coldKey</span><span class="p">}</span><span class="s2">`</span><span class="p">)</span>

    <span class="c1">// Use proxy call for setting children</span>
    <span class="kd">const</span> <span class="nx">children</span> <span class="o">=</span> <span class="p">[[</span><span class="nx">MAX_U64</span><span class="p">,</span> <span class="nx">childKey</span><span class="p">]]</span>
    <span class="kd">const</span> <span class="nx">chkTx</span> <span class="o">=</span> <span class="nx">api</span><span class="p">.</span><span class="nx">tx</span><span class="p">.</span><span class="nx">subtensorModule</span><span class="p">.</span><span class="nf">setChildren</span><span class="p">(</span><span class="nx">hotKey</span><span class="p">,</span> <span class="nx">netuid</span><span class="p">,</span> <span class="nx">children</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">chkTx</span><span class="dl">'</span><span class="p">,</span> <span class="nx">chkTx</span><span class="p">.</span><span class="nf">toHuman</span><span class="p">());</span>

    <span class="kd">const</span> <span class="nx">proxyCall</span> <span class="o">=</span> <span class="nx">api</span><span class="p">.</span><span class="nx">tx</span><span class="p">.</span><span class="nx">proxy</span><span class="p">.</span><span class="nf">proxy</span><span class="p">(</span><span class="nx">coldKey</span><span class="p">,</span> <span class="dl">'</span><span class="s1">ChildKeys</span><span class="dl">'</span><span class="p">,</span> <span class="nx">chkTx</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">proxyCall</span><span class="dl">'</span><span class="p">,</span> <span class="nx">proxyCall</span><span class="p">.</span><span class="nf">toHuman</span><span class="p">());</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`Sending CHK transaction for netUID </span><span class="p">${</span><span class="nx">netuid</span><span class="p">}</span><span class="s2">.`</span><span class="p">);</span>

    <span class="kd">const</span> <span class="nx">proxyCallHash</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">proxyCall</span><span class="p">.</span><span class="nf">signAndSend</span><span class="p">(</span><span class="nx">proxy</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`Bittensor chk successfully: </span><span class="p">${</span><span class="nx">proxyCallHash</span><span class="p">.</span><span class="nf">toHex</span><span class="p">()}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>

<span class="nf">main</span><span class="p">().</span><span class="k">catch</span><span class="p">(</span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">).</span><span class="k">finally</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">());</span>
</code></pre></div></div>

<p>Note that the above script does <strong>not</strong> require a coldkey mnemonic - <strong>only a proxy account mnemonic</strong>. This means that coldkey assets are not at risk in this transfer - only proxy actions can take place.</p>

<h2 id="multi-proxy-architecture">Multi-Proxy Architecture</h2>

<p>Childkeys follow a one-to-many relationship with proxy accounts. Proxy accounts can be uniquely used for different operations (e.g., one account for Staking, another for Childkeying). A coldkey’s active proxies can be monitored using the <code class="language-plaintext highlighter-rouge">proxy::proxies(address)</code> method.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">api</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">proxy</span><span class="p">.</span><span class="nf">proxies</span><span class="p">(</span><span class="nx">coldKeyAddress</span><span class="p">,</span> <span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Current proxies:</span><span class="dl">"</span><span class="p">,</span> <span class="nx">result</span><span class="p">.</span><span class="nf">toHuman</span><span class="p">());</span> <span class="p">});</span>
</code></pre></div></div>

<h2 id="proxy-risk-mitigations">Proxy Risk Mitigations</h2>

<p>While proxy accounts do provide enhanced security around direct asset loss, they should still be used with caution. For example, insecure usage of the “Staking” role can lead to the swapping of arbitrary quantities of alpha tokens (at high slippage), and insecure usage of the “Registration” role can lead to burned registration fees. <strong>Secure key practices around proxy accounts remain a top priority when using proxies</strong>.</p>

<p>If a proxy account compromise is detected, <code class="language-plaintext highlighter-rouge">proxy::removeProxy(delegate, proxyType, delay)</code> may be used to revoke permissions.</p>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">async</span> <span class="kd">function</span> <span class="nf">removeProxy</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="p">{</span> <span class="nx">ApiPromise</span><span class="p">,</span> <span class="nx">WsProvider</span><span class="p">,</span> <span class="nx">Keyring</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">@polkadot/api</span><span class="dl">'</span><span class="p">);</span>
    <span class="kd">const</span> <span class="p">{</span> <span class="nx">cryptoWaitReady</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">@polkadot/util-crypto</span><span class="dl">'</span><span class="p">);</span>

    <span class="c1">// Environment variables</span>
    <span class="kd">const</span> <span class="nx">mnemonic</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">COLD_KEY_MNEMONIC</span><span class="p">;</span> <span class="c1">// Coldkey mnemonic (should be securely stored)</span>
    <span class="kd">const</span> <span class="nx">proxyAddress</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">PROXY_ADDRESS</span><span class="p">;</span> <span class="c1">// Address of the proxy being removed</span>
    <span class="kd">const</span> <span class="nx">providerEndpoint</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">PROVIDER_ENDPOINT</span><span class="p">;</span> <span class="c1">// Bittensor Substrate node</span>

    <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">mnemonic</span> <span class="o">||</span> <span class="o">!</span><span class="nx">proxyAddress</span> <span class="o">||</span> <span class="o">!</span><span class="nx">providerEndpoint</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Error: Missing required environment variables.</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">// Initialize crypto</span>
    <span class="k">await</span> <span class="nf">cryptoWaitReady</span><span class="p">();</span>
    <span class="kd">const</span> <span class="nx">provider</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">WsProvider</span><span class="p">(</span><span class="nx">providerEndpoint</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">api</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">ApiPromise</span><span class="p">.</span><span class="nf">create</span><span class="p">({</span> <span class="nx">provider</span> <span class="p">});</span>

    <span class="c1">// Initialize keyring and coldkey account</span>
    <span class="kd">const</span> <span class="nx">keyring</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Keyring</span><span class="p">({</span> <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">sr25519</span><span class="dl">'</span> <span class="p">});</span>
    <span class="kd">const</span> <span class="nx">coldKey</span> <span class="o">=</span> <span class="nx">keyring</span><span class="p">.</span><span class="nf">addFromUri</span><span class="p">(</span><span class="nx">mnemonic</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`Removing proxy </span><span class="p">${</span><span class="nx">proxyAddress</span><span class="p">}</span><span class="s2"> from coldkey </span><span class="p">${</span><span class="nx">coldKey</span><span class="p">.</span><span class="nx">address</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>

    <span class="c1">// Create removeProxy transaction</span>
    <span class="kd">const</span> <span class="nx">removeProxyTx</span> <span class="o">=</span> <span class="nx">api</span><span class="p">.</span><span class="nx">tx</span><span class="p">.</span><span class="nx">proxy</span><span class="p">.</span><span class="nf">removeProxy</span><span class="p">(</span><span class="nx">proxyAddress</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Any</span><span class="dl">'</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">removeProxyTx:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">removeProxyTx</span><span class="p">.</span><span class="nf">toHuman</span><span class="p">());</span>

    <span class="c1">// Sign and send transaction</span>
    <span class="kd">const</span> <span class="nx">removeProxyHash</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">removeProxyTx</span><span class="p">.</span><span class="nf">signAndSend</span><span class="p">(</span><span class="nx">coldKey</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`Proxy removed successfully. Tx Hash: </span><span class="p">${</span><span class="nx">removeProxyHash</span><span class="p">.</span><span class="nf">toHex</span><span class="p">()}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>

<span class="nf">removeProxy</span><span class="p">().</span><span class="k">catch</span><span class="p">(</span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">).</span><span class="k">finally</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="nx">process</span><span class="p">.</span><span class="nf">exit</span><span class="p">());</span>
</code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<p>At Unit 410, we take a detailed approach to Bittensor validation. By combining performant hardware, secure practices, and innovative tooling, we have engineered solutions designed to maximize stability and uptime.</p>

<p>If topics and insights like this are interesting to you, check out our open roles <a href="https://unit410.com/#jobs">here</a>.</p>]]></content><author><name>GitHub User</name><email>your-email@domain.com</email></author><category term="engineering" /><category term="bittensor" /><summary type="html"><![CDATA[By Wesley Graham, Infrastructure Engineer]]></summary></entry></feed>