<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jakhongir Tashpulatov</title>
    <description>The latest articles on DEV Community by Jakhongir Tashpulatov (@bczak).</description>
    <link>https://dev.to/bczak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4174971%2F9648a28a-a436-460b-a6ae-bcad862096de.png</url>
      <title>DEV Community: Jakhongir Tashpulatov</title>
      <link>https://dev.to/bczak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bczak"/>
    <language>en</language>
    <item>
      <title>Meet Thyme Gate</title>
      <dc:creator>Jakhongir Tashpulatov</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:45:56 +0000</pubDate>
      <link>https://dev.to/thymelabs/meet-thyme-gate-5eda</link>
      <guid>https://dev.to/thymelabs/meet-thyme-gate-5eda</guid>
      <description>&lt;p&gt;Every onchain app needs an RPC endpoint. Usually that's yet another vendor with its own dashboard, its own keys and its own bill, separate from the rest of your backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://gate.thymelabs.io" rel="noopener noreferrer"&gt;Thyme Gate&lt;/a&gt;&lt;/strong&gt; is the RPC product in &lt;a href="https://thymelabs.io" rel="noopener noreferrer"&gt;thyme/labs&lt;/a&gt;. It gives you a JSON-RPC endpoint per chain, with keys scoped to your project and usage you can actually read. It sits in the same workspace as our onchain automation (Flow) and hosted subgraphs (Atlas).&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep your client, change the URL
&lt;/h2&gt;

&lt;p&gt;There's no custom SDK or transport. If your code speaks JSON-RPC, it works with Gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a key
&lt;/h3&gt;

&lt;p&gt;Keys belong to a project. Name one for each app or environment, such as &lt;code&gt;orders-production&lt;/code&gt; or &lt;code&gt;orders-staging&lt;/code&gt;, so you can see each one's traffic and revoke them separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Choose a network
&lt;/h3&gt;

&lt;p&gt;Pick a mainnet or testnet. The console shows the exact HTTPS URL for every network available to your key.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Send a request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GATE_RPC_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with viem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mainnet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem/chains&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mainnet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GATE_RPC_URL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBlockNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reads, logs and transaction submissions all go through the same interface. To switch chains, change the endpoint and the chain config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supported networks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Chain&lt;/th&gt;
&lt;th&gt;Chain ID&lt;/th&gt;
&lt;th&gt;Networks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Mainnet, Sepolia&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;137&lt;/td&gt;
&lt;td&gt;Mainnet, Amoy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimism&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Mainnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BNB Smart Chain&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;td&gt;Mainnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unichain&lt;/td&gt;
&lt;td&gt;1301&lt;/td&gt;
&lt;td&gt;Sepolia&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Need another chain? Email &lt;a href="mailto:support@thymelabs.io"&gt;support@thymelabs.io&lt;/a&gt; and tell us which one.&lt;/p&gt;

&lt;h2&gt;
  
  
  See the traffic behind the bill
&lt;/h2&gt;

&lt;p&gt;RPC bills are often a black box. Gate's console shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requests and errors&lt;/strong&gt; by network&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute units by RPC method&lt;/strong&gt;, so you can see what's driving cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traffic and last use&lt;/strong&gt; per API key&lt;/li&gt;
&lt;li&gt;Your &lt;strong&gt;free allowance&lt;/strong&gt; through the billing cycle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If one method is eating your budget, you'll see it in the method breakdown instead of finding out on the invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keys you control
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keys are scoped to a project, and only workspace owners and admins can create or revoke them.&lt;/li&gt;
&lt;li&gt;To rotate a key without downtime, create a new one, deploy the new URL, check that traffic moved, then revoke the old key.&lt;/li&gt;
&lt;li&gt;Revoking a key stops future requests that use it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One tip: the endpoint URL contains your key. Keep it in server-side config, not in a browser bundle, and redact it from logs and screenshots.&lt;/p&gt;

&lt;p&gt;Need more throughput or a signed SLA? &lt;a href="mailto:support@thymelabs.io?subject=Thyme%20Gate%20Enterprise"&gt;Talk to us about enterprise&lt;/a&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Get an endpoint: &lt;a href="https://gate.thymelabs.io" rel="noopener noreferrer"&gt;https://gate.thymelabs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Quickstart: &lt;a href="https://flow.thymelabs.io/docs/gate/quickstart" rel="noopener noreferrer"&gt;https://flow.thymelabs.io/docs/gate/quickstart&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your client is ready. Give it an endpoint. What are you building? Tell us in the comments. 👇&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>rpc</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>Meet Thyme Atlas</title>
      <dc:creator>Jakhongir Tashpulatov</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:43:46 +0000</pubDate>
      <link>https://dev.to/thymelabs/meet-thyme-atlas-5219</link>
      <guid>https://dev.to/thymelabs/meet-thyme-atlas-5219</guid>
      <description>&lt;p&gt;If your app shows onchain data like balances, positions, trade history or vault TVL, you've probably either scanned blocks yourself or run a Graph Node. Both mean babysitting infrastructure instead of shipping features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://atlas.thymelabs.io" rel="noopener noreferrer"&gt;Thyme Atlas&lt;/a&gt;&lt;/strong&gt; hosts your subgraphs. You deploy with the Graph CLI you already use, Atlas indexes your contracts on managed Graph Nodes, and you query decoded events and entity state over GraphQL. There's no node to run and no instance to size.&lt;/p&gt;

&lt;p&gt;Atlas is part of &lt;a href="https://thymelabs.io" rel="noopener noreferrer"&gt;thyme/labs&lt;/a&gt;, in the same workspace as our RPC (Gate) and onchain automation (Flow).&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the Graph CLI, change the node
&lt;/h2&gt;

&lt;p&gt;Your &lt;code&gt;subgraph.yaml&lt;/code&gt;, schema and mappings stay as they are. Atlas accepts the same build and IPFS upload that &lt;code&gt;graph-cli&lt;/code&gt; already produces.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a subgraph
&lt;/h3&gt;

&lt;p&gt;Name it in the console. It lives in a project, with the same members and billing as the rest of your workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create a deploy key
&lt;/h3&gt;

&lt;p&gt;Deploy keys belong to the project. The secret is shown once, and revoking a key stops new deploys within seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Run &lt;code&gt;graph deploy&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;graph codegen &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; graph build

graph deploy my-subgraph &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--node&lt;/span&gt; https://deploy.atlas.thymelabs.io/ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ipfs&lt;/span&gt; https://ipfs.atlas.thymelabs.io/api/v0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--deploy-key&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ATLAS_DEPLOY_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--headers&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Authorization&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Bearer &lt;/span&gt;&lt;span class="nv"&gt;$ATLAS_DEPLOY_KEY&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version-label&lt;/span&gt; v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That uploads the build, creates a release and starts indexing.&lt;/p&gt;

&lt;h2&gt;
  
  
  One endpoint, keys you control
&lt;/h2&gt;

&lt;p&gt;Every subgraph gets an HTTPS GraphQL endpoint. It works with Graph Client, Apollo, urql or plain &lt;code&gt;fetch&lt;/code&gt;. Send a query key as a bearer token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ATLAS_QUERY_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ATLAS_QUERY_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{ vaults(first: 5) { id tvl } }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can scope a query key to a whole project or to a single subgraph.&lt;/li&gt;
&lt;li&gt;Revoked keys stop working within seconds.&lt;/li&gt;
&lt;li&gt;Every release has a GraphiQL playground, so you can test queries before you write code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ship the next version without downtime
&lt;/h2&gt;

&lt;p&gt;Re-indexing usually means downtime or juggling two endpoints. In Atlas, each deploy is an &lt;strong&gt;immutable release&lt;/strong&gt; that indexes alongside production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can follow indexing progress, health and errors for each release.&lt;/li&gt;
&lt;li&gt;Once the new release has caught up, promote it. Your production endpoint switches to it.&lt;/li&gt;
&lt;li&gt;If something looks wrong, roll back to the previous release in seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your app keeps querying the same URL the whole time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supported networks
&lt;/h2&gt;

&lt;p&gt;Atlas indexes these chains from nodes we run ourselves. In &lt;code&gt;subgraph.yaml&lt;/code&gt;, set the network to the name Graph Node expects:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Network&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;network:&lt;/code&gt; value&lt;/th&gt;
&lt;th&gt;Chain ID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mainnet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum Sepolia&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sepolia&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;11155111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;&lt;code&gt;matic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;137&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon Amoy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;polygon-amoy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;80002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimism&lt;/td&gt;
&lt;td&gt;&lt;code&gt;optimism&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BNB Smart Chain&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bsc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unichain Sepolia&lt;/td&gt;
&lt;td&gt;&lt;code&gt;unichain-testnet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1301&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Need another chain? Email &lt;a href="mailto:support@thymelabs.io"&gt;support@thymelabs.io&lt;/a&gt; and tell us which one.&lt;/p&gt;

&lt;p&gt;Indexing a large protocol or need dedicated capacity? &lt;a href="mailto:support@thymelabs.io?subject=Thyme%20Atlas%20Enterprise"&gt;Talk to us about enterprise&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Deploy a subgraph: &lt;a href="https://atlas.thymelabs.io" rel="noopener noreferrer"&gt;https://atlas.thymelabs.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bring the subgraph, and we'll run the node. Got a subgraph you'd like to move over? Tell us in the comments. 👇&lt;/p&gt;

</description>
      <category>web3</category>
      <category>graphql</category>
      <category>subgraph</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Meet Thyme Flow</title>
      <dc:creator>Jakhongir Tashpulatov</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:34:34 +0000</pubDate>
      <link>https://dev.to/thymelabs/meet-thymelabs-rpc-subgraphs-on-chain-automation-and-gas-sponsorship-in-one-workspace-3a95</link>
      <guid>https://dev.to/thymelabs/meet-thymelabs-rpc-subgraphs-on-chain-automation-and-gas-sponsorship-in-one-workspace-3a95</guid>
      <description>&lt;p&gt;A lot of onchain apps need something to happen on a clock: harvest rewards, rebalance a vault, top up a balance, close an expired position. The usual options are a cron box holding a hot private key, or a keeper network you have to fund and trust with your contracts.&lt;/p&gt;

&lt;p&gt;We built &lt;strong&gt;&lt;a href="https://flow.thymelabs.io" rel="noopener noreferrer"&gt;Thyme Flow&lt;/a&gt;&lt;/strong&gt; so you don't have to pick either. You write a TypeScript task that decides what to do. Flow runs it on a schedule and sends the calls from &lt;strong&gt;a Safe you own&lt;/strong&gt;, through a role you can revoke whenever you want. We never hold the keys to your account.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Write a task
&lt;/h3&gt;

&lt;p&gt;A task is plain TypeScript. It reads live chain state and returns the calls to send, or decides to skip this run. You never sign anything in your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@thyme-labs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parseAbi&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseAbi&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function harvest()&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function pendingRewards() view returns (uint256)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;minRewards&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coerce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;minRewards&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pendingRewards&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Skip this run: not worth the gas yet.&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;minRewards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;canExec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; pending`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;canExec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;harvest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The task context gives you what you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ctx.args&lt;/code&gt;&lt;/strong&gt;: typed inputs, validated against your Zod schema&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ctx.client&lt;/code&gt;&lt;/strong&gt;: a viem client for chain reads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ctx.secrets&lt;/code&gt;&lt;/strong&gt;: only the project secrets bound to this executable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ctx.storage&lt;/code&gt;&lt;/strong&gt;: JSON state that persists between runs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A run that returns &lt;code&gt;canExec: false&lt;/code&gt; sends no transaction. One run can return up to 32 calls, which are executed atomically in one transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Run it locally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @thyme-labs/cli
thyme init my-automation
thyme run harvest-rewards &lt;span class="nt"&gt;--simulate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI runs your task in a local sandbox and simulates the returned calls against a real RPC. Nothing is signed or broadcast.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Upload it
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;thyme upload harvest-rewards &lt;span class="nt"&gt;--tag&lt;/span&gt; v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This bundles the task into an immutable, checksummed release. A tag can't be overwritten, so you always know which code is running.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Schedule it
&lt;/h3&gt;

&lt;p&gt;In the console, create an executable. You pick the Safe it runs from, its arguments and secrets, and when it runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cron&lt;/strong&gt;: any standard cron expression. The console reads it back in plain words before you save.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interval&lt;/strong&gt;: from every 30 seconds up to once a day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook&lt;/strong&gt;: up to ten named, secret URLs per executable. Each request body is validated against your task's schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flow handles the schedule, the signing and the gas from there. Every run shows up in the execution logs, with its decision, calls and transaction hash.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it stays safe
&lt;/h2&gt;

&lt;p&gt;Automation that can move funds needs a tight trust model. Here's ours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your Safe stays yours
&lt;/h3&gt;

&lt;p&gt;Your wallet owns the Safe. Flow gets a scoped executor role through the &lt;a href="https://github.com/gnosisguild/zodiac-modifier-roles" rel="noopener noreferrer"&gt;Zodiac Roles&lt;/a&gt; module, and that role can only:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;call the &lt;strong&gt;contract addresses and functions you allowlist&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;send calls with &lt;strong&gt;zero native value&lt;/strong&gt;, and never &lt;code&gt;delegatecall&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The executor can't widen its own role or administer your Safe. Only you, as the owner, can approve a broader scope, and you sign that change yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revoke any time
&lt;/h3&gt;

&lt;p&gt;Remove the role or the module from your Safe and Flow can't submit anything, ever. That's a normal Safe transaction, and it doesn't need our permission. Pausing an executable in the console stops runs too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check before you sign
&lt;/h3&gt;

&lt;p&gt;When you set up a Safe profile, the console checks the deployed contract code against pinned hashes before it asks for your signature.&lt;/p&gt;

&lt;p&gt;You don't have to take our word for it, either. &lt;code&gt;thyme verify roles-profile&lt;/code&gt; independently rebuilds the setup from pinned Safe and Zodiac Roles versions, then checks the signature request or the deployed contracts against the allowlist you intended. It never calls the Thyme API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Declare what your code may call
&lt;/h3&gt;

&lt;p&gt;A task can ship a &lt;code&gt;permissions.json&lt;/code&gt; that lists the contracts and functions it needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"calls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"arg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vault"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"harvest()"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flow checks that your Safe's role covers these calls before you can enable an executable. At runtime, any call outside the declaration is rejected before it's submitted. The manifest isn't a grant: only your signed Safe scope can give access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets stay out of your code
&lt;/h3&gt;

&lt;p&gt;Secrets live in a vault, not in your bundle. You bind each one to the executables that need it, and Flow redacts known secret values from logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Isolated runs
&lt;/h3&gt;

&lt;p&gt;Every cloud run executes in an isolated sandbox with a 30-second timeout. Each executable's storage is versioned and locked, so overlapping runs can't overwrite each other's state.&lt;/p&gt;

&lt;h3&gt;
  
  
  An honest caveat
&lt;/h3&gt;

&lt;p&gt;Roles scopes restrict the &lt;strong&gt;target contract and function&lt;/strong&gt;, not the arguments. If you allow &lt;code&gt;transfer&lt;/code&gt; or &lt;code&gt;approve&lt;/code&gt;, the task chooses the recipient and amount. Only allow functions you'd trust your task with, and keep only the funds the automation needs in the Safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Works with your coding agent
&lt;/h2&gt;

&lt;p&gt;Paste one prompt into Claude Code, Codex, Cursor or another coding agent, and it learns the &lt;code&gt;thyme&lt;/code&gt; CLI. It can write and test a task, upload it, create the executable, set the schedule and read run logs.&lt;/p&gt;

&lt;p&gt;Creating a Safe profile, or widening what it may call, still needs your signature in the console.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Start building: &lt;a href="https://flow.thymelabs.io" rel="noopener noreferrer"&gt;https://flow.thymelabs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Quickstart: &lt;a href="https://flow.thymelabs.io/docs/getting-started/quickstart" rel="noopener noreferrer"&gt;https://flow.thymelabs.io/docs/getting-started/quickstart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SDK and CLI (open source, MIT): &lt;a href="https://github.com/thyme-labs/sdk" rel="noopener noreferrer"&gt;https://github.com/thyme-labs/sdk&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flow is part of &lt;a href="https://thymelabs.io" rel="noopener noreferrer"&gt;thyme/labs&lt;/a&gt;, which also offers RPC (Gate) and hosted subgraphs (Atlas) in the same workspace.&lt;/p&gt;

&lt;p&gt;What would you automate first? Tell us in the comments. 👇&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
