SpartanDev: 16/08/21–22/08/21

Contract contributors finalise the dynamic weight change-over and begin the automated testing…

Summary

The GitHub wizards have been throwing down hard, working their way through the CodeArena improvements. The contributors are getting really excited to put the improvements through the literal wringer, to provide a seamless, quality DeFi experience for the Shieldwall.

New updates and information on the next phase of SP are what you're here for though, so feast your eyes on the commits below.

CodeArena Donations

So, the community is aware that a Spartan community member contributed the full USD$96,000 CodeArena bounty + contest costs (in advance) on behalf of the wider community, to ensure that there were no delays in commencing our contest in our nominated date window.

Obviously, that community member still remains out of pocket as the target has not yet quite been reached (very close now though, thank you) so whilst there is no time-pressure to donate to the cause; it would still be greatly appreciated.

Originally, the CodeArena page was created for a specific purpose, but it will now be repurposed to act as a general community wallet donation page for other ongoing project costs. Future donations will help take the financial burden off the community members who have covered these costs since the project’s inception (hosting, domains, RPCs, Combot license, APIs etc) and potentially allow us to build a reserve for the community bounties again.

Now, before we continue — a big, massive thank you to all the Spartans who generously donated to the codeArena campaign; this seemed out of reach only a couple of months ago when the idea was floated; it’s incredible to see how far we can go in such a short period of time.

Donate Here:https://dapp.spartanprotocol.org/codearena

feeBurn Update (from earlier in the week)

Spartan Socials — Twitter

Top Spartan Tweet:

Top Community Tweet:

Check out this generous legend who put up an awesome NFT prize for a lucky warrior that donates to the crowdfunding community wallet!

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, and 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

Once these tasks above are completed, the CodeArena report will be published, and Spartans will be able to review the final list of findings to understand how the changes already implemented into Spartan Protocol (in the PostC5 repository) fit into this greater picture.

As discussed previously, we continue to build and refine code in parallel with the CodeArena post-contest actions.

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 et al.)
  • COMPLETED (& ONGOING) — Work with token-tracking informational websites to ensure new token info is up-to-date (BSCscan, CoinGecko, CoinMarketCap et al.)

SpartanContracts

  • 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
  • IN PROGRESS — Update automated testing
  • 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

DAppV2

  • COMPLETED (& ONGOING) — Set up a reliable index of history scoped to contracts (use this for positions page etc)
  • Update the DApp to suit the contract changes
  • 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 — SpartanContractsV2

contracts/BondVault.sol

  1. BASE changed to immutable
  2. Updated line-by-line commenting
  3. purgeDeployer() changed to external
  4. Added require() to all .transfer() & .transferFrom()

contracts/Dao.sol

  1. BASE changed to immutable
  2. Updated line-by-line commenting
  3. Removed unused variables:
  • secondsPerEra variable (call BASE contract variable instead)
  • proposalCount variable (not required; same value as currentProposal)
  • MemberDetails struct (no longer used)
  • mapPID_votes mapping (no longer used)
  • mapPIDMember_votes (no longer used)

4. Change weight logic to be calculated on the fly instead of locked in at the time of weightChange:

  • Added mapPIDMember_hasVoted mapping — signal user’s support of a proposal
  • Added mapPIDAsset_votes mapping — tally staked units instead of weights
  • Simplify events; weight args no longer required
  • Added weightChange() modifier for all chain transactions that would change a user’s weight— checks if user has voted; if they have it updates their staked balances against the proposal

5. Constructor changes:

  • Added address(0) checks (input validation)
  • Removed proposalCount = 0 assignment (redundant)
  • Removed secondsPerEra assignment (variable removed)

6. Modifiers changed:

  • deposit() — added weightChange
  • withdraw() — added weightChange
  • bond() — added weightChange; removed nonReentrant
  • _handleTransferIn() — added nonReentrant
  • claimAll() — added weightChange

7. Updated function access:

  • deposit() — public changed to external
  • harvest() — public changed to external
  • _claim() — public changed to internal (so weightChange modifier doesn’t need to be called every claim within a batch of claimAll)
  • unvoteProposal() — public changed to external
  • ROUTER() — public changed to external
  • UTILS() — public changed to external
  • BONDVAULT() — public changed to external
  • DAOVAULT() — public changed to external
  • POOLFACTORY() — public changed to external
  • SYNTHFACTORY() — public changed to external
  • RESERVE() — public changed to external
  • SYNTHVAULT() — public changed to external
  • LEND() — public changed to external

8. Added a DaoVault deposit blockshift (prevent deposit + withdraw in the same block):

  • deposit()
  • bond()

9. withdraw() function changes:

  • Removed the vote removal fee and logic to calculate it

10. harvest() — get secondsPerEra from BASE instead of inheriting on deploy

11. listBondAsset() —added require() to revert this function if a proposal is open, to stop proposal votes going out of sync along with overflow/underflow issues

12. Added require() to all .transfer() & .transferFrom()

13. Removed typestring validation from new proposal functions — Catch-all during finaliseProposal() will catch invalid typestrings for ‘malicious users’ — UI handles the typestring with a constant list for ‘accidental mistake’ users:

  • newActionProposal()
  • newParamProposal()
  • newAddressProposal()

14. Get currentProposal from storage once and store in memory —save gas:

  • newActionProposal() via _checkProposal() return
  • newParamProposal() via _checkProposal() return
  • newAddressProposal() via _checkProposal() return
  • newGrantProposal() via _checkProposal() return
  • _checkProposal()
  • voteProposal()
  • unvoteProposal()
  • pollVotes()
  • _finalise() handed in via argument
  • cancelProposal()
  • finaliseProposal()

15. Removed returns from functions:

  • newActionProposal()
  • newParamProposal()
  • newAddressProposal()
  • newGrantProposal()
  • _checkProposal()
  • voteProposal()
  • unvoteProposal()

16. payFee() — removed minAmount and changed it back to a flat fee due to not being used in removeVote anymore

17. voteProposal() function changes:

  • Added require() to make sure user has not already voted for proposal (prevent votes going out of sync)
  • Removed the ‘check status’ logic from this function to make voting less gas-expensive (anyone can manually call this now via pollVotes)
  • This now calls _addVotes() to record the user’s current vault balances for the proposal; this will only emit an event if the units > 0 (event log poisoning)

18. unvoteProposal() function changes:

  • Added require() to ensure a proposal is open & use has already voted for proposal (prevent votes going out of sync)
  • Remove the removalFee logic
  • This now calls _removeVotes() to remove the user’s current vault balances from the proposal; this will only emit an event if the units > 0 (event log poisoning)

19. pollVotes() — added function:

  • This function polls all votes for the proposal and their respective weight value vs the total DAO weight to see if consensus has been reached
  • If consensus has been reached (quorum or majority depending on proposal type) the proposal is shifted into the finalisation stage

20. _finalise() — hand in arguments for PID & type to save gas

21. cancelProposal() function changes:

  • Added require() to make sure a proposal is in an open status
  • Loops all vault assets and resets the mapped vote-balance for each to 0

22. Added the Synth.Realise() functionality to the DAO:

  • Added ‘REALISE’ typestring to newAddressProposal()
  • Added _realise() function which grabs the proposed address (synth address) and calls Synth.realise() to calculate the value of the LP collateral vs the synthSupply and burns any premium/excess LP tokens to funnel that dead-ownership down the underlying liquidity providers

23. _removeCuratedPool() — this now also delists the relevant bond asset (if it's bond-listed)

24. _completeProposal() — this now also loops vault assets and zeros them out

25. Replaced countVotes() with two internal functions:

  • _addVotes() — loops vault assets and adds the user’s staked balances to the proposal
  • _removeVotes() — loops vault assets and removes the user’s staked balances from the proposal

26. hasMajority() && hasQuorum() changes:

  • Dynamically get the cumulative total weight of the DAO and weight of votes in the proposal to determine whether consensus has been reached

27. Added getter/helper functions for new nested mappings:

  • getProposalAssetVotes() — gets the current mapped total units of an asset staked in favour of a proposal
  • memberVoted() — checks if the user has voted in support of the proposal

contracts/DaoVault.sol

  1. Updated line-by-line comments

2. Changed BASE variable to immutable

3. Added purgeDeployer() function

4. getMemberLPWeight() — fixed to calculate cumulative instead of individual

5. getMemberPoolDepositTime() — added helper to retrieve members deposit time per asset

contracts/Pool.sol

  1. Updated line-by-line commenting
  2. Changed variables:
  • BASE — changed to immutable
  • TOKEN — changed to immutable
  • poolCAP — renamed to synthCap
  • collateral — added (for mint/burn synth virtualization)
  • minSynth — added (min basis points to virtualise in mint/burn synth calculations)
  • lastMonth — changed to public

3. Function access changed:

  • SYNTH() — changed to public

4. Constructor changes:

  • Added address(0) validation for _base && _token
  • minSynth set at 500 (5%)

5. _transfer() — user senderBalance from memory instead of storage; small gas saver

6. _burn() — user accountBalance from memory instead of storage; small gas saver

7. Added require() to all .transfer() & .transferFrom()

8. mintSynth() function changes:

  • Changed synth require() to SynthFactory.isSynth() (better source of truth)
  • Added virtualisation on the SPARTA side too
  • Added minimum SPARTA virtualisation to spread some of the benefits away from the first synth minters to the liquidity providers
  • Added minimum TOKEN virtualisation to spread some of the benefits away from the first synth minters to the liquidity providers
  • Increase the collateral mapping by the SPARTA coming in

9. burnSynth() function changes:

  • Added virtualisation on the SPARTA side too
  • Added minimum SPARTA virtualisation to spread some of the benefits away from the last synth burners to the liquidity providers
  • Added minimum TOKEN virtualisation to spread some of the benefits away from the last synth burners to the liquidity providers
  • Decrease the collateral mapping by the share of the total supply vs SYNTH units burned (the last burner will always make collateral = 0; no realise-style function required)

10. Removed virtualisation from all non-synth calculations:

  • _swapBaseToToken()
  • _swapTokenToBase()

11. minimumSynth() — added setter for minSynth variable

contracts/Reserve.sol

  1. BASE changed to immutable
  2. Updated line-by-line commenting
  3. Constructor added address(0) validation
  4. Added require() to all .transfer()

contracts/Router.sol

  1. Updated line-by-line commenting
  2. Changed variables:
  • BASE — changed to immutable
  • WBNB— changed to immutable

3. Function’s modifier changes:

  • _handleTransferIn() — added nonReentrant

4. Constructor changes:

  • Added address(0) validation for _base && _wbnb
  • removed lastMonth = 0 assignment

5. Adding liquidity symmetrically no longer has a base/SPARTA amount argument; it is instead calculated off the tokenAmount to be symmetrical based on pool’s ratio:

  • addLiquidity() — removed inputBase argument
  • addLiquidityForMember() — removed inputBase argument
  • removed the input validation — already required in upstream _handleTransferIn()
  • Calculates the inputBase using spot value of inputToken

6. addLiquidityAsymForMember() — adding liquidity asymmetrically now swaps half of the input and adds symmetrically instead:

  • Performs a Router.swapTo() then transfers the roughly symmetrical assets in and calls Pool.addForMember() — previously this just jammed the asset in one-sided and did a slip adjustment calculation to penalise the member at a slightly higher rate than a swap-add. Both implementations are valid and fine, but we have gone with a more symmetrical-leaning approach with the router and utils contracts

7. zapLiquidity() — changed to flow of actions to be a ~symmetrical add instead:

  • Remove SPARTA + TOKEN1 liquidity (POOL1)
  • Swap TOKEN1 to SPARTA (now we have SPARTA + SPARTA)
  • Swap half of SPARTA to TOKEN2
  • Add SPARTA + TOKEN2 liquidity (~symmetrical to POOL2)
  • Previously it was:
  • Remove SPARTA + TOKEN1 liquidity (POOL1)
  • Swap TOKEN1 to SPARTA (now we have SPARTA + SPARTA)
  • Add SPARTA + SPARTA liquidity (asymmetrical to POOL2)

8. Store PoolFactory interface in memory (save gas) && use PoolFactory.isPool to validate pool (better source of truth):

  • addLiquidityForMember()
  • addLiquidityAsymForMember()
  • removeLiquidityExact()
  • removeLiquidityAsym()
  • buyTo()
  • sellTo()
  • swapTo()
  • swapAssetToSynth()
  • swapSynthToAsset()

9. Add require() for input to be valid (event poisoning):

  • removeLiquidityExact()
  • removeLiquidityAsym()
  • swapAssetToSynth()
  • swapSynthToAsset()

10. Added require() for all .transfer() & .transferFrom()

11. removeLiquidityAsym() — added in dividend logic

12. swapTo() — removed ‘feey’ from dividend (dividend already happens upstream for ‘feey’ in sellTo)

13. swapSynthToAsset() function changes:

  • Added in isPool validation for the synthPool too
  • Added in the transfer of SPARTA to the swapPool
  • Split the dividends into their respective pools

14. Added changeMinimumSynth() setter for Pool.minimumSynth()

contracts/Synth.sol

  1. Updated line-by-line commenting
  2. Changed variables:
  • BASE — changed to immutable
  • TOKEN — changed to immutable
  • POOL— changed to immutable
  • genesis — changed to immutable

3. _transfer() — user senderBalance from memory instead of storage; small gas saver

4. _burn() — user accountBalance from memory instead of storage; small gas saver

5. Constructor changes:

  • Added address(0) validation for _base && _token && _pool

contracts/Utils.sol

  1. Updated line-by-line commenting
  2. Changed variables:
  • BASE — changed to immutable
  • one— changed to private constant

3. Constructor changes:

  • Added address(0) validation for _base

4. PoolDataStruct struct changes:

  • Removed: fees, volume and txCount (redundant)

5. Added getSynth() helper

6. getSlipAdjustment() — changed to pure

7. calcLiquidityUnits() — changed to pure

8. Changed pricing helpers to default to ‘withPool’

contracts/poolFactory.sol

  1. Updated line-by-line commenting
  2. Changed variables:
  • BASE — changed to immutable
  • WBNB— changed to immutable

3. Constructor changes:

  • Added address(0) validation for _base && _wbnb

4. Remove createPool() function; handle all pool listings through createPoolADD() now

5. createPoolADD() — adjusted to be able to handle BNB pool now that createPool() has been removed

6. addCuratedPool() — add require() to prevent adding curated pool if there is an open proposal (prevent votes getting out of sync)

7. removeCuratedPool() — removes synth from ‘isSynth’ in the SynthFactory too

8. _handleTransferIn() — added in nonReentrant modifier and changed the function to handle BNB now that createPoolADD() needs to handle the BNB pool

contracts/synthFactory.sol

  1. Updated line-by-line commenting
  2. Changed variables:
  • BASE — changed to immutable
  • WBNB — changed to immutable
  • DEPLOYER — added variable

3. Constructor changes:

  • Added address(0) validation for _base && _wbnb
  • Added DEPLOYER = msg.sender

4. Added onlyDao() modifier

5. createSynth() changes:

  • Store PoolFactory interface in memory (save gas)
  • Map in synth to the arrays and record as isSynth

6. Added removeSynth() function to handle removing a synth as valid

contracts/synthVault.sol

  1. Updated line-by-line commenting
  2. Changed variables:
  • BASE — changed to immutable
  • totalWeight — removed
  • stakedSynthAssets — removed
  • lastMonth — changed to public
  • genesis — changed to immutable

3. Constructor changes:

  • Added address(0) validation for _base

4. Changed mappings:

  • mapMemberSynth_weight — removed
  • mapMemberTotal_weight — removed
  • mapTotalSynth_balance — added
  • isStakedSynth — removed
  • isSynthMember — removed

5. Simplified events; removed the weight-related args

6. deposit() — added input validation and isSynth check

7. _deposit() — removed weight-changing logic; handle only balances instead

8. changeWeight() — removed function

9. harvestSingle() — check isSynth and handle balances instead of weights

10. calcCurrentReward() — added in a limit to the maxclaim possible based on reserve’s holdings

11. calcReward() function changed to use dynamic weights from mapped balances:

  • Get the weights dynamically from all scopes (member/vault/synth)
  • Calculate the vaults claim
  • Calculate the asset’s share of that claim
  • Calculate the user’s share of that claim

12. getMemberSynthWeight() — this works out the weights used in the above calcReward() function

13. withdraw() function changes:

  • Validate basis points (event poisoning)
  • Updated balances rather than weights

14. Add require() to .transfer() & .transferFrom()

15. Removed Unused helper functions:

  • getMemberWeight()
  • getStakeSynthLength()
  • getMemberSynthWeight()

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:

0x588f82a66eE31E59B88114836D11e3d00b3A7916

Incentivized liquidity and synthetic asset generation for Binance Smart Chain. https://SpartanProtocol.org