SpartanDev: 09/08/21–15/08/21

Mid August update highlighting the simplification of dividend calculations, dynamic weights at the value-extraction stage and a whole lot more!


Happy Monday, warriors of the shield wall.

Contributors are continuing to work through improvements thanks to the feedback provided from the codeArena audit. Things are shaping up well with automated testing to commence shortly, allowing stress testing of the updated V2 code.

Keep your eyes locked on the GitHub activity if you want to know more.

We still need your support

We still need your support. All donations help ensure the V2 Protocol contracts get a thorough review from many angles. We are very close to meeting our initial raise objectives. Please help us kick it over the line.

If you can donate, big or small, every contribution helps this community project achieve its full goal of $96k as soon as possible to ensure that Spartan Protocol is in a prime position to release the V2 contracts and DApp onto mainnet.

Donate Here:

It’s time to upgrade your tokens

No problems; upgrade today

You can use the Spartan Protocol Upgrade DApp to upgrade your SPARTAv1 tokens to SPARTAv2 yourself.

Upgrade DApp

Bit-Rush Crypto has created a video guide on using the SpartanProtocol Upgrade DApp — timestamp 3:20. Nice work SPARTANS!!

feeBurn Update

Spartan Socials — Twitter

Top Impressions:

Top Engagement:

Top Community Mention:

SpartanSocials — Medium

SpartanSocials — Telegram

Contributor’s Focus

It has been a busy few months, and devoted community members will have seen the contributors working hard through the previously listed focus points.

Now that the codeArena audit is complete, it seems a suitable time to clear completed items off the checklist. Remove the noise; enjoy.

CodeArena Contest

  • COMPLETED — triage and prioritise the feedback submitted from the CodeArena wardens during the contest to prepare for the judges
  • IN PROGRESS — work through the post-contest tasks with the C4 judges & team for the eventual allocation of awards to security wardens
  • IN PROGRESS — communicate with security wardens to clarify/expand on feedback

SPARTA V2 (Token)

  • COMPLETED & ONGOING — Work with DEXs & aggregators to ensure up-to-date information on the new SPARTA token (retiring the previous contract address) (1inch, PancakeSwap etc)
  • COMPLETED & ONGOING — Work with token-tracking informational websites to ensure new token info is up-to-date (BSCscan, CoinGecko, CoinMarketCap etc)


  • COMPLETED — Sort and prioritise all CodeArena submissions into contract scopes along with tags based on ‘actionable’ or ‘discussion points’
  • IN PROGRESS — Implementing refinements to contracts to address C4 & contributor feedback since the C4 contest code-freeze
  • Deploy updated V2 contracts to BSC testnet for at least 1 week of community stress testing
  • Deploy completed V2 contracts to BSC mainnet
  • COMPLETED & ONGOING — Continue the code review process within the community


  • COMPLETED & ONGOING — Set up a reliable index of history scoped to contracts (use this for positions page etc)
  • IN PROGRESS — Use the new testnet subgraph to build a more lightweight positions page for V2

After Mainnet

  • Enable Bond allocations to replenish TVL into the V2 pools
  • March onwards with our original goals of building the decentralised, yield-generating synthetics protocol on Binance Smart Chain

GitHub Activity — SpartanSite


  • Converted static footer to a js component


  • Converted static header to a js component


  • Converted scrollUpButton to a component


  • Removed header, footer etc from all HTML pages and injected the components instead

GitHub Activity — SpartanContractsV2


  1. Weight logic changes to help reduce opportunity-size from manipulation:
  • Removed weight-related variables & mappings (we will no longer store weight as history and instead calculate it on the fly whenever it is being used)
  • Added mappings/variables to focus on staked/locked balances instead of weights

2. Added require check to constructor to make sure _base handed in is not address(0)

3. Replace tokenAddress arguments with poolAddress and removed the PoolFactory.getPool() reliance:

  • depositForMember()
  • calcBondedLP()
  • claimForMember()
  • getMemberDetails()

4. Replaced updateWeight() with getMemberLPWeight():

  • Removed ‘asset’ arg; this now gets the totalWeight of all relevant assets for the user
  • Added return of memberWeight & totalWeight
  • Removed getPool logic and instead get an array of relevant pools from the DAO
  • This function now simply loops the array handed back from DAO.listedBondPools() and gets a NET sum of the Utils.getPoolShareWeight() for both the member’s balance and the total held in the vault. This means that any manipulation of weight will scale all members of the same vault equally (in percentage terms; which is how the weight is utilized)

5. Added getMemberPoolBalance() helper to get a member’s mapped balance by poolAddress


  1. Added ‘operational’ status to close off the functionality of a DAO in the event it is retired/upgraded:
  • Added ‘running’ variable (bool)
  • Added operational() modifier which requires ‘retire’ to be false
  • Yet to add in setter to be able to flip this true/false

2. Added ‘running’ status to pause proposal functionality in the DAO:

  • Added ‘retire’ variable (bool)
  • Added isRunning() modifier which requires ‘running’ to be true
  • Set this as false in the constructor so that a newly deployed DAO will not have proposal functionality until the weight is distributed enough

3. Added in LEND placeholders to potentially have an easier addition of lending contracts later down the track

4. setGenesisFactors() — changed uint32 args to uint256

5. depositLPForMember() changes:

  • Renamed to deposit()
  • Replaced ‘member’ with msg.sender
  • Removed forced harvest logic now that weight is calculated dynamically (threat is removed) however the issue of user’s time being reset by a deposit is now not fault-safe; this can be prevented however via the UI (check user’s available harvest and warn them away from depositing until they have harvested)

6. withdraw() — changed this so that only the weight is updated in the current proposal rather than removing their entire vote weight whenever a user withdraws

7. calcReward() — adapted to call the new weight functions

8. listBondAsset() — added require check to ensure the asset is not already listed for bond

9. delistBondAsset() — added require check to ensure the asset is listed and valid for removal; update the ‘current’ array accordingly

10. bond() — removed forced harvest logic

11. _handleTransferIn() — changed to handle deflationary assets

12. claimAll() function changes:

  • Simplified this to loop an array from the argument instead of a potentially unbounded list of bond assets
  • The UI knows exactly what assets to claim already; so it makes sense to shift the computation away from the EVM here
  • Changed member to msg.sender

13. payFee() adapted for reuse; takes in an ‘amount’ arg now:

  • newActionProposal()
  • newParamProposal()
  • newAddressProposal()
  • newGrantProposal()
  • withdraw()
  • removeVote()

13. newActionProposal() — added input validation of the typeStr to prevent invalid proposal type

14. newParamProposal() — added input validations to prevent invalid proposals

15. newAddressProposal() — added input validations to prevent invalid proposals

16. newGrantProposal() changes:

  • Added input validation to prevent invalid proposals
  • Added a cap on the max grant size using the daoClaim basisPoints (10% by default)

17. voteProposal() — nested the event emission inside a conditional to resist event spamming

18. removeVote() changes:

  • Nested the event emission inside a conditional to resist event spamming
  • Added the removalFee logic for a small SPARTA fee on removal

19. finaliseProposal() changes:

  • Require the proposal is open
  • Require the proposal is not finalised
  • Added catch-all else statement to close a proposal that is invalid

20. _delistBondingAsset — added in the handling of the currently listed bond assets array to match delistBondAsset()

21. completeProposal() — added in BondVault.totalWeight for emitted event

22. hasMajority() — simplified the if/else into a simple check

22. hasQuorum() — simplified the if/else into a simple check

23. hasMinority() — removed the function entirely; not required

24. isEqual() — simplified the if/else into a simple check


  1. Weight logic changes to help reduce opportunity-size from manipulation:
  • Removed weight-related variables & mappings (we will no longer store weight as history and instead calculate it on the fly whenever it is being used)
  • Added mappings/variables to focus on staked/locked balances instead of weights

2. Added require to constructor to ensure _base is not address(0)

3. depositLP() — adjust balance mappings rather than weights

4. getMemberLPWeight() function:

  • Removed increaseWeight() function
  • Removed decreaseWeight() function
  • getMemberLPWeight() created to handle looping the current DaoVault assets and getting a dynamic weight figure
  • memberWeight && totalWeight handed back as the return

5. withdraw() — zero out the mapped member->pool staked balance instead of handling the weight-change calc here

6. getMemberWeight() — removed function

7. getMemberPoolWeight() — removed function


  1. Added new pool initiation period which disables withdrawing liquidity until a time period has passed since the creation of the pool (defaults to 7 days)
  2. Factored the ‘oldRate’ calc to account for rounding (squared the numerator)
  3. removeForMember() — added require check to ensure withdrawals arent possible until the initiation period has passed (see #1)
  4. safetyCheck() — factored the calculations to account for wei rounding
  5. setInitiation() — added setter for the initiation period variable


  1. Calls the DAO for the protocol addresses (accounted for upgraded reserve contract via DAO):
  • Removed the address variables for DAO, ROUTER etc
  • Instead, call the source of truth (DAO) from the constant (BASE/SPARTA contract) and derive the current addresses from there


  1. Changes to dividends:
  • Removed most variables relating to the dividend calculation (maxTrades, normalAverageFee etc)
  • Removed most functions, setters and helpers relating to dividends

2. addLiquidityForMember() — added require check to ensure input is not 0 (gas / UX saver for end user)

3. getsDividend() — removed addTradeFee(fee)

4. addDividend():

  • Gets the reserve balance
  • Gets the dividend max share of the reserve balance
  • Sends in a dividend that is equal to the size of the tradeFee if all conditions are valid
  • This creates a situation where the dividend (opportunity) is equal to the trade’s slip fee (cost of attack) if the attacker owns 100% of the pool (and if we ignore gas), and is more expensive than the opportunity in all other situations
  • This also obviously makes the dividend logic a lot cheaper as we don't need an array or a bunch of calculations & storage calls for every dividend-worthy swap


  1. Permissioned Synth.realise() to onlyDAO to potentially set up realise() to be only callable by the Liquidity providers that the function directly affects


  1. getPoolShareWeight() — hand in poolAddress rather than tokenAddress
  2. calcShare() — require total > 0 to avoid division by zero confusion
  3. calcLiquidityUnits() — added line-comments to help readability & added zero-division handling
  4. getSlipAdjustment() — added line-comments to help readability & added zero-division handling
  5. calcLiquidityHoldings() — added zero-division handling
  6. calcSwapOutput() — added zero-division handling
  7. calcSwapFee() — added zero-division handling
  8. calcSpotValueInBaseWithPool() — added zero-division handling
  9. calcSpotValueInTokenWithPool() — added zero-division handling
  10. calcSwapValueInBaseWithPool() — added zero-division handling


  1. Added vaultAssets array to handle ‘current’ vault-enabled assets
  2. addCuratedPool() — add new curated asset to vaultAssets array
  3. removeCuratedPool — remove curated asset from vaultAssets array
  4. _handleTransferIn() — simplified and removed return


  1. Removed DEPLOYER variable and assignment in constructor
  2. Removed onlyDAO()
  3. Removed purgeDeployer()


  1. Added purgeDeployer()
  2. setParams() — changed args to be more readable
  3. Changed deposit functions to use msg.sender instead of member
  4. Refactor weight changing logic into a new function changeWeight()
  5. harvestAll() — changed to be handed an array of assets to claim instead of looping the history (the UI knows exactly what assets to claim already)
  6. changeWeight() function added:
  • Requires the synth to be valid
  • Requires emissions to be on
  • Handle the balance/weight mappings updates

7. harvestSingle() changes:

  • Require lockup period passed before harvesting
  • Added Pool.sync() here to prevent someone from using the internal tsf function to piggy-back a synthVault deposit on top of harvest() thereby bypassing the lockup period
  • Removed the Synth.realise() from here to partition the realise function to only be triggered by the DAO

8. addFee() — add to memory from storage to save gas

Project Information

Official Links

Community Contribution

Spartan Protocol is at its core, a community-driven and led project. In this vein, the more contributors the better. There is a great opportunity for community members to contribute by making LP reward analysis tools, etc.

Recently, community members have been graciously funnelling in to contribute to explainer articles, ideas and even $SPARTA donations to support the growth of the platform.

Engage with the community and contributors

Where to find out about all the latest updates or suggest improvements — get involved.

Community Bounty Wallet

Whilst there is no treasury nor contributor allocations, there was a public community bounty wallet set up a while ago to help handle donations from the community and other incentive programs (BNB from the Binance BUIDl program was sent here) which can be viewed here:


Incentivized liquidity and synthetic asset generation for Binance Smart Chain.