Tinyman
Tinyman is a decentralised exchange on Algorand. Beyond swaps, its web client runs governance, liquid staking, and trigger (limit) and recurring (DCA) orders, where each transaction has to show clear progress and status while the chain confirms it. The flows are built to feel seamless even though every action waits on the blockchain.
- Year
- 2021 - 25
- Role
- Frontend Developer
- Stack
- React, TypeScript, JavaScript, HTML / CSS, tinyman-js-sdk, algosdk, TradingView
- Link
- tinyman.org ↗
Governance: locking and voting mechanism
Level 3 · Governance components: Governance
Governance gives TINY holders who lock their tokens a say in Tinyman's future and in which liquidity pools receive farming rewards. It also keeps them engaged: governors with at least 5,000 TINY power get lower fees on trigger and recurring orders.
TINY holders become governors by locking their tokens. Their TINY power decays linearly over time, so locking more or extending the lock keeps it up. Only governors can vote on farming and governance proposals: a governor who locks before a proposal is created can vote on it, and anyone else can vote on the next one. Each governor's history sits in one table, and a line chart shows how their power changes.
One lock form covers creating a lock, extending it, adding TINY, or doing both in one step, and a successful lock refreshes the governor's position. Votes use each governor's TINY power as of the proposal's creation time, read from the historic governance API, so adding TINY mid-vote can't change the result. Farming votes split weight across up to 8 pools, adding to 100%. Each weight can be set with the +/- buttons in 5% steps, typed in directly, or picked from quick-amount buttons. The Farming tab shows the current cycle, which lists the pools elected by the last vote, and the next cycle, where governors vote. Once a vote is submitted, the next-cycle table locks and shows the percentages cast.
3,746 governors have locked 252.53M TINY: 39.75% of the 635.27M in circulation, and about 25% of the 1B total supply. Five governance proposals have been voted on, and governors accepted four. Weekly rewards of about 815K TINY are shared by governors, so claims move roughly 3M TINY a month.
Every action that moves funds or changes state follows the same three steps: collect the input, validate the data and balances, then prepare and execute the transactions. A hook builds the transactions with tinyman-js-sdk and checks balances, such as whether there is enough ALGO, before the wallet opens. A shared helper asks the connected wallet to sign, then submits the transactions to Algorand.
Overview shows a governor's position and rewards. Claiming rewards builds the claim transactions and checks that the account has enough ALGO for fees before the wallet opens. After a successful claim, the app waits for some seconds to reload the governor details, so the page doesn't show stale figures. Withdrawing an expired lock refreshes the wallet account, so the locked amount updates. The transactions table lists past locks, votes and claims from the governance API.
Lock handles creating a lock, extending it, adding TINY, or doing both in one step. The form checks whether the account already has a lock, which decides the transaction path. After a lock succeeds, the app refreshes the wallet account and then the governor details, so the new TINY power appears.
Proposals lists every proposal from the governance API, and each proposal opens to show its details. A notification dot appears in the app header, footer and tabs whenever a new proposal opens. Its state is stored in the browser's local storage and read live by each component, so dismissing it needs no server request, and a newly active proposal brings it back. Changes sync across open tabs. Opening the proposal marks it as seen, which clears the dot. Creating a proposal is available only when the account's TINY power meets the requirement.
Farming shows the pools elected by the last cycle and the pools open for the next cycle, with the number of governors who backed each one. The vote form tracks each pool's weight and the remaining percentage in one reducer, which keeps the total at 100%. The form also blocks a vote for more than 8 pools. Once the vote succeeds, the next-cycle table locks and shows the percentages the user cast. When the voting period starts, the next farming cycle shows a new-proposal dot, which clears when the user enters the tab.
Accounts is a read-only directory of governors. It reads governor statistics and a paged list from the governance API. Search and filters are kept in the URL, so a filtered view can be shared. No transactions happen on this tab.
A vote on a proposal reads the governor's TINY power as of the proposal's creation time, so adding TINY mid-vote can't change the weight. After the transaction is sent, the app waits for Algorand to confirm it, about 3 seconds, then fetches the proposal again with the account address, so the vote shows on the page.
Governance gives TINY holders who lock their tokens a say in Tinyman's future and in which liquidity pools receive farming rewards. It also keeps them engaged: governors with at least 5,000 TINY power get lower fees on trigger and recurring orders.
TINY holders become governors by locking their tokens. Their TINY power decays linearly over time, so locking more or extending the lock keeps it up. Only governors can vote on farming and governance proposals: a governor who locks before a proposal is created can vote on it, and anyone else can vote on the next one. Each governor's history sits in one table, and a line chart shows how their power changes.
One lock form covers creating a lock, extending it, adding TINY, or doing both in one step, and a successful lock refreshes the governor's position. Votes use each governor's TINY power as of the proposal's creation time, read from the historic governance API, so adding TINY mid-vote can't change the result. Farming votes split weight across up to 8 pools, adding to 100%. Each weight can be set with the +/- buttons in 5% steps, typed in directly, or picked from quick-amount buttons. The Farming tab shows the current cycle, which lists the pools elected by the last vote, and the next cycle, where governors vote. Once a vote is submitted, the next-cycle table locks and shows the percentages cast.
3,746 governors have locked 252.53M TINY: 39.75% of the 635.27M in circulation, and about 25% of the 1B total supply. Five governance proposals have been voted on, and governors accepted four. Weekly rewards of about 815K TINY are shared by governors, so claims move roughly 3M TINY a month.
Every action that moves funds or changes state follows the same three steps: collect the input, validate the data and balances, then prepare and execute the transactions. A hook builds the transactions with tinyman-js-sdk and checks balances, such as whether there is enough ALGO, before the wallet opens. A shared helper asks the connected wallet to sign, then submits the transactions to Algorand.
Overview shows a governor's position and rewards. Claiming rewards builds the claim transactions and checks that the account has enough ALGO for fees before the wallet opens. After a successful claim, the app waits for some seconds to reload the governor details, so the page doesn't show stale figures. Withdrawing an expired lock refreshes the wallet account, so the locked amount updates. The transactions table lists past locks, votes and claims from the governance API.
Lock handles creating a lock, extending it, adding TINY, or doing both in one step. The form checks whether the account already has a lock, which decides the transaction path. After a lock succeeds, the app refreshes the wallet account and then the governor details, so the new TINY power appears.
Proposals lists every proposal from the governance API, and each proposal opens to show its details. A notification dot appears in the app header, footer and tabs whenever a new proposal opens. Its state is stored in the browser's local storage and read live by each component, so dismissing it needs no server request, and a newly active proposal brings it back. Changes sync across open tabs. Opening the proposal marks it as seen, which clears the dot. Creating a proposal is available only when the account's TINY power meets the requirement.
Farming shows the pools elected by the last cycle and the pools open for the next cycle, with the number of governors who backed each one. The vote form tracks each pool's weight and the remaining percentage in one reducer, which keeps the total at 100%. The form also blocks a vote for more than 8 pools. Once the vote succeeds, the next-cycle table locks and shows the percentages the user cast. When the voting period starts, the next farming cycle shows a new-proposal dot, which clears when the user enters the tab.
Accounts is a read-only directory of governors. It reads governor statistics and a paged list from the governance API. Search and filters are kept in the URL, so a filtered view can be shared. No transactions happen on this tab.
A vote on a proposal reads the governor's TINY power as of the proposal's creation time, so adding TINY mid-vote can't change the weight. After the transaction is sent, the app waits for Algorand to confirm it, about 3 seconds, then fetches the proposal again with the account address, so the vote shows on the page.
Liquid staking: stake, restake and unstake
Level 3 · Liquid staking components: Liquid staking
Liquid staking lets ALGO holders stake, help secure and decentralise Algorand, and earn rewards, while keeping their funds usable. They receive tALGO, a token they can trade or redeem for ALGO with no lock-up. They can also add it to liquidity pools and join farming programs for extra rewards.
Users stake ALGO and receive tALGO, a liquid token that keeps earning Algorand staking rewards and can be traded or redeemed for ALGO at any time with no lock-up. Re-staking tALGO into stALGO adds TINY rewards, for governors with at least 5,000 TINY power.
The UI calls mint and burn on TinymanTAlgoClient, and increaseStake, decreaseStake and claimRewards on TinymanSTAlgoClient, both from tinyman-js-sdk. Before each transaction runs, the app checks that the account holds enough of the asset being used (ALGO, tALGO or stALGO) and enough ALGO for the fees, and shows a clear message if it doesn't. Restaking and unstaking show the fee before signing. Each operation is one wallet approval through a confirm, sign, then success-or-retry screen. Restaking is a governor perk: the restake form is enabled only for committed Tinyman governors who hold at least 5,000 TINY, checked against the governance API. Governors who restake can claim their TINY rewards from the restake page.
tALGO's value grows as staking rewards accrue. It started at 1 ALGO per tALGO and was about 1.0989 ALGO as of October 16, 2026. The same mint and burn also run from the swap page. After the implementation, Tinyman's trading volume crossed $100 million USD for the first time in the protocol's history, in January 2025. There are currently 35 million tALGO in circulation.
LiquidStakingFlow owns one reducer and context holding both SDK clients, shared statistics and the form state (amounts, view, form type). The tab comes from the URL; the reducer switches between the form and a confirmation page that picks one of four confirmation views. Each operation has its own hook (useStakeAlgo, useUnstakeAlgo, useRestakeTAlgo, useUnstakeStAlgo, useClaimRestakeRewards) with the same steps: build with the SDK, sign and submit with a shared helper, report progress through one async state. The swap page reuses the same operations: swapping ALGO to tALGO sends the mint transaction, and swapping tALGO to ALGO sends the burn transaction. The exchange rate is read from the tALGO app's global state; APRs and rewards come from the analytics API.
Liquid staking lets ALGO holders stake, help secure and decentralise Algorand, and earn rewards, while keeping their funds usable. They receive tALGO, a token they can trade or redeem for ALGO with no lock-up. They can also add it to liquidity pools and join farming programs for extra rewards.
Users stake ALGO and receive tALGO, a liquid token that keeps earning Algorand staking rewards and can be traded or redeemed for ALGO at any time with no lock-up. Re-staking tALGO into stALGO adds TINY rewards, for governors with at least 5,000 TINY power.
The UI calls mint and burn on TinymanTAlgoClient, and increaseStake, decreaseStake and claimRewards on TinymanSTAlgoClient, both from tinyman-js-sdk. Before each transaction runs, the app checks that the account holds enough of the asset being used (ALGO, tALGO or stALGO) and enough ALGO for the fees, and shows a clear message if it doesn't. Restaking and unstaking show the fee before signing. Each operation is one wallet approval through a confirm, sign, then success-or-retry screen. Restaking is a governor perk: the restake form is enabled only for committed Tinyman governors who hold at least 5,000 TINY, checked against the governance API. Governors who restake can claim their TINY rewards from the restake page.
tALGO's value grows as staking rewards accrue. It started at 1 ALGO per tALGO and was about 1.0989 ALGO as of October 16, 2026. The same mint and burn also run from the swap page. After the implementation, Tinyman's trading volume crossed $100 million USD for the first time in the protocol's history, in January 2025. There are currently 35 million tALGO in circulation.
LiquidStakingFlow owns one reducer and context holding both SDK clients, shared statistics and the form state (amounts, view, form type). The tab comes from the URL; the reducer switches between the form and a confirmation page that picks one of four confirmation views. Each operation has its own hook (useStakeAlgo, useUnstakeAlgo, useRestakeTAlgo, useUnstakeStAlgo, useClaimRestakeRewards) with the same steps: build with the SDK, sign and submit with a shared helper, report progress through one async state. The swap page reuses the same operations: swapping ALGO to tALGO sends the mint transaction, and swapping tALGO to ALGO sends the burn transaction. The exchange rate is read from the tALGO app's global state; APRs and rewards come from the analytics API.
Trigger and Recurring orders
Level 3 · Order components: Orders
Instant swaps trade at the current price. Trigger and recurring orders let users swap only when the price reaches their target, or spread a purchase over time, without watching the market.
Trigger orders are set with a price ratio and an expiry. Recurring orders are set with an iteration count, an iteration interval and an optional price range. Once the form is filled in, the app prepares the transactions needed to place the order and saves it to the order tables. In the open orders table, users can cancel or withdraw an order, and claim the amounts already swapped at the requested price. The order history table holds past orders. Users can follow updated prices on a TradingView chart beside the form, and hide it when they don't need it.
Orders can't be placed until the user sets up an order app from the UI. Until the order app creation transaction is signed, the form stays unavailable. The trigger and recurring forms share one form component, which keeps the selected assets to trade in context, so the assets and amounts carry across the Swap, Trigger and Recurring tabs.
After a one-time setup, placing a trigger or recurring order takes one wallet approval. Order apps are versioned, so when the contracts change, users update their order app from the UI. Order status and recurring order iterations come from the order history API, refetched every 20 seconds while open orders are shown, so the UI doesn't poll the chain.
OrderingClient is created once per account and network and kept in SwapPageContext, so the Trigger tab, the Recurring tab and the order history share one instance. Selected assets and amounts live in a separate SwapPageFormContext, shared with the Swap tab. OrderFormContainer decides what to render: create app, update app, or the form for the order type. Each action has its own hook (usePutOrder, usePutRecurringOrder, useManageOrderApplication, useCancelOrder, useClaimPartialOrder) with the same steps: prepare with the SDK, sign with the shared wallet signer, submit, show progress. Trigger and Recurring share everything except the form and the hook for placing the order.
Instant swaps trade at the current price. Trigger and recurring orders let users swap only when the price reaches their target, or spread a purchase over time, without watching the market.
Trigger orders are set with a price ratio and an expiry. Recurring orders are set with an iteration count, an iteration interval and an optional price range. Once the form is filled in, the app prepares the transactions needed to place the order and saves it to the order tables. In the open orders table, users can cancel or withdraw an order, and claim the amounts already swapped at the requested price. The order history table holds past orders. Users can follow updated prices on a TradingView chart beside the form, and hide it when they don't need it.
Orders can't be placed until the user sets up an order app from the UI. Until the order app creation transaction is signed, the form stays unavailable. The trigger and recurring forms share one form component, which keeps the selected assets to trade in context, so the assets and amounts carry across the Swap, Trigger and Recurring tabs.
After a one-time setup, placing a trigger or recurring order takes one wallet approval. Order apps are versioned, so when the contracts change, users update their order app from the UI. Order status and recurring order iterations come from the order history API, refetched every 20 seconds while open orders are shown, so the UI doesn't poll the chain.
OrderingClient is created once per account and network and kept in SwapPageContext, so the Trigger tab, the Recurring tab and the order history share one instance. Selected assets and amounts live in a separate SwapPageFormContext, shared with the Swap tab. OrderFormContainer decides what to render: create app, update app, or the form for the order type. Each action has its own hook (usePutOrder, usePutRecurringOrder, useManageOrderApplication, useCancelOrder, useClaimPartialOrder) with the same steps: prepare with the SDK, sign with the shared wallet signer, submit, show progress. Trigger and Recurring share everything except the form and the hook for placing the order.