POLTech: Proof of Liquidity goes Social
friend.tech, despite how you might feel about it, has redefined how we engage with content and the monetary value we ascribe to influencers' attention and insights.
We introduce POLTech, which integrates friend.tech's social trading elements into Berachain's Proof of Liquidity (PoL) paradigm. POLTech showcases the adaptability of PoL beyond the typical "stake your ERC20 receipt token to earn BGT
". Interested? Let's dive in.
Overview
In this article, we walk through the following:
- How the POLTech app works and its features
- A deep dive into the smart contracts intrinsically linking POLTech's share trading with PoL staking
POLTech App Walkthrough
Check out the app here: https://poltech.vercel.app/
Share Trading
Buy and sell shares associated with specific addresses using BERA
tokens.
Automatic Staking for BGT
Every share purchase is automatically staked in a Rewards Vault, granting eligibility to BGT
rewards.
Claim the BGT which has accrued to your account from your share purchases on the Leaderboard page.
Chat
Owning an address' shares entitles users to enter an exclusive chat with them and everyone else who owns shares.
Pretty cool right? Give this a spin at https://poltech.vercel.app/
POLTech Smart Contracts
The astute reader might be asking - "wait the demo user didn't stake in a Reward Vault, how are they earning BGT
??"
Very reasonable question, because in many cases, users expect to have to stake their assets on the Vaults dashboard. But less is known about the feature where smart contracts can stake on behalf of users.
Contracts can use the delegateStake
function on Reward Vaults to manage their users' PoL staking positions
The following diagram illustrates how the different elements interact:
Users can see the live POLTech contract here: https://bartio.beratrail.io/address/0x2B1B76961C0e38DD79FEf76611f71465d4b0B817/contract/80084/code
Automatic Staking with delegateStake
The POLTech
constructor creates a new dummy staking token, which the POLTech
contract has control over, and whose sole purpose is to represent its users' BGT
staking positions.
Below, we see how the POLTech contract creates a new PoLStakingToken
, and subsequently a Reward Vault from the Factory:
constructor() {
address vaultFactory = 0x2B6e40f65D82A0cB98795bC7587a71bfa49fBB2B;
stakingToken = new PoLStakingToken(address(this));
polVault = IBerachainRewardsVault(
IBerachainRewardsVaultFactory(vaultFactory).createRewardsVault(
address(stakingToken)
)
);
}
When a user buys shares, the contract automatically stakes the equivalent value in the Vault (in the buyShares
function):
// Mint and stake according to the value of shares bought
stakingToken.mint(address(this), buyPrice);
stakingToken.approve(address(polVault), buyPrice);
polVault.delegateStake(msg.sender, buyPrice);
The PoL entitlement buyers get (through delegateStake
) is dictated by the buyPrice
(how much BERA
they paid for the shares).
Let's quickly explore how share prices work on POLTech...
Dynamic Pricing Mechanism
The POLTech
contract implements a bonding curve for share pricing, so that price scales with demand:
function getBuyPrice(
address subject,
uint256 amount
) public view returns (uint256 totalCost, uint256 endPrice) {
uint256 price = getSharePrice(subject);
totalCost = 0;
for (uint256 i = 0; i < amount; i++) {
totalCost += price;
price = price + PRICE_CHANGE_FACTOR; // Each purchase pumps price
}
endPrice = price;
return (totalCost, endPrice);
}
Just Reverse this Logic When Selling Shares Right?
To quickly recap:
- The price of an address' shares go up the more people that buy it
- The more you spend buying shares, the more you get staked on your behalf in the Vault
The opposite is true where selling makes share prices go down. So prices are expected to go up and down, creating a dynamic market for attention.
So what happens to your Vault/PoL stake if you sell your shares when the price is higher or lower than when you purchased?
Well that's a problem, because we can't just simply unstake the amount someone gets back from a sale. They might have paid a less for those shares after all!
FIFO Lot Tracking
To solve the problem of tracking PoL stakes as share prices fluctuate, POLTech
uses a FIFO lot tracking system to maintain records of what each user initially paid for their shares:
struct Lot {
uint256 shares;
uint256 stakedAmount;
}
mapping(address => mapping(address => Lot[])) public shareLots;
// When buying shares (buyShares):
shareLots[msg.sender][subject].push(
Lot({shares: amount, stakedAmount: buyPrice})
);
// When selling shares (sellShares):
while (sharesToSell > 0) {
Lot storage lot = shareLots[msg.sender][subject][0];
// Process the oldest lot first
if (lot.shares <= sharesToSell) {
// Sell entire lot
totalStakeToWithdraw += lot.stakedAmount;
sharesToSell -= lot.shares;
removeLot(msg.sender, subject);
} else {
// Sell part of the lot
uint256 partialStake = (lot.stakedAmount * sharesToSell) / lot.shares;
totalStakeToWithdraw += partialStake;
lot.shares -= sharesToSell;
lot.stakedAmount -= partialStake;
sharesToSell = 0;
}
}
// After calculating totalStakeToWithdraw (still in sellShares)
polVault.delegateWithdraw(msg.sender, totalStakeToWithdraw);
stakingToken.burn(address(this), totalStakeToWithdraw);
The FIFO lots work as follows:
- When shares are bought, a new
Lot
is created and added to the user's array of lots for that subject/address. EachLot
stores:- the number of shares bought; and
- the amount staked (corresponding to the purchase price)
- When selling shares, the contract processes the oldest lots first (FIFO)
- If a
Lot
is fully consumed, it's removed. If only part of a lot is sold, the remaining shares and staked amount of thatLot
are updated - This process continues until all shares to be sold are accounted for, finally calling
delegateWithdraw
with thetotalStakeToWithdraw
Your accounting professor would be pleased.
Conclusion
If you've made it this far, you've gained valuable insights into how POLTech cleverly integrates Proof of Liquidity within a SocialFi context. Let's recap the key points we've covered:
- Automatic Staking:
delegateStake
is powerful for automatically managing users' PoL stakes. Conversely usedelegateWithdraw
when users leave/sell - FIFO Lot Tracking: POLTech accurately tracks users' stakes even as share prices fluctuate
More examples on how PoL can be adapted to other interesting applications coming soon!
đ» Full Code Repository
If you want to see the final code and see other guides, check out POLTech Code.
đ ïž Want To Build More?
If youâre looking to dive deeper into the details, take a look at our Berachain Docs.
Looking For Dev Support?
Make sure to join our Berachain Discord server and check out our developer channels to ask questions.
â€ïž Donât forget to show some love for this article đđŒ