This research piece introduces the concept of big vector, a new data structure we utilize for Typus V2 to mitigate the limitations of vectors and dynamic fields on Sui. The primary goal of big vector is to explore its potential for applications that require hyper-scalability within a single transaction, all while keeping costs at a minimum.
Dynamic field made its debut with Sui 0.13.0 in October 2022. These “fields” are unique in that they are associated with an object rather than being serialized within a vector. When working with dynamic fields, access occurs through Move function during execution, as opposed to being loaded upfront when the object is initially loaded.
Although dynamic fields don’t have an absolute capacity limit, there is a restriction on accessing a maximum of 1,000 objects per transaction. If the number of users surpasses this limit, a single transaction cannot accommodate them all. For instance, with 10,000 users, it would necessitate splitting the operation into batches of at least 10 transactions. Furthermore, the gas fees for accessing objects within dynamic fields follow a fixed charging mechanism, meaning that as more reads and accesses are executed, the associated gas fees increase.
To put this in perspective, let’s examine an example from the Typus V1 framework. In order to mitigate the 1,000 objects limit, we rewrote our code by splitting what would’ve been one single step into 17 steps.
(The following requires a basic understanding of Typus’ architecture, please refer to https://docs.typus.finance/architecture for further information.)
(0) settle
(0) settle_performance_fee_balance
(1n) settle_bidder_balance
(2n) settle_adjust_active_user_share_ratio
(3n) settle_adjust_deactivating_user_share_ratio
(4n) settle_reset_bidder_user_share
(5n) settle_remained_performance_fee_combination
(6n) settle_rock_n_roll_deactivating
(7n) settle_rock_n_roll_active
(8n) activate_share
(9) activate_vault
(10) new_auction
(11) delivery_premium
(12n) refund_active
(13n) refund_deactivating
(14n) delivery_active
(15n) delivery_deactivating
(16n) delivery_bidder
Splitting the process into 17 transactions has a noticeable impact on execution speed, causing a significant slowdown, while also leading to increased gas fees. The fundamental problem lies in the high cost associated with dynamic field accesses.
Executing a single round for a vault containing 20,000 users typically incur gas fees ranging from approximately 30 to 70 SUI. Given there are currently 14 vaults, 7 weekly and 7 daily, our monthly operational expenses for settlement gas fees will fall within the range of 7,140 to 16,660 SUI.
To scale up and accommodate more underlying assets, strike prices, and expirations, we inevitably need to expand beyond our existing 14 vaults. However, such an expansion would substantially elevate our operational costs due to the escalating gas fees.
Even if gas fees weren’t a significant concern, splitting transactions introduces additional complexity to the contracts. Certain transactions need to be completed before the next one could commence, the approach involves adding a multitude of temporary fields and implementing new functions to carry out the tasks originally performed in each round.
This introduces additional dependencies and diminishes the overall robustness of the code. The resulting issue is that if there’s a logical error in accessing these temporary fields, leading to calculation errors, it not only necessitates a significant amount of time to pinpoint the problem within the complex code but also demands additional manpower to rectify the contract.
Let’s examine a scenario we’ve encountered in the past. This example occurred before any “transaction failed” events took place. In a prior internal investigation, we noticed a decrease in our depositor user share, even though none of the recent rounds had resulted in in-the-money occurrences. Therefore, in theory, the user shares should have remained consistent with the values from the preceding days.
Upon closer examination, we discovered that the issue stemmed from not entirely restricting user operations during the step settle process (steps 0 through 7). The presence of n in this context indicates that it involves addressing the challenge of encountering 1,000 dynamic field accesses and necessitates multiple runs to resolve.
(0) settle
(0) settle_performance_fee_balance
(1n) settle_bidder_balance
(2n) settle_adjust_active_user_share_ratio
(3n) settle_adjust_deactivating_user_share_ratio
(4n) settle_reset_bidder_user_share
(5n) settle_remained_performance_fee_combination
(6n) settle_rock_n_roll_deactivating
(7n) settle_rock_n_roll_active
(8n) activate_share
(9) activate_vault
(10) new_auction
(11) delivery_premium
(12n) refund_active
(13n) refund_deactivating
(14n) delivery_active
(15n) delivery_deactivating
(16n) delivery_bidder
The scenario where this issue arises occurs when a user, during a particular in-the-money settlement phase, executes an unsubscribe action during step 2n. The purpose of step 2n is to align the user’s share and balance at a 1:1 ratio to avoid minute balance discrepancies that might result from subsequent floating-point calculations.
However, if a user performs an unsubscribe action during the process, particularly when a portion of users has already achieved the 1:1 ratio while other remain unadjusted, the user who hasn’t completed the adjustment yet (holding a higher share and balance compared to their actual value) would transfer their share to the deactivating sub vault. As a result, this user would essentially take a partial loss, effectively distributing this loss proportionally among those who remain in the active sub vault.
Subsequent rounds following this incident would necessitate adjustments back to the 1:1 ratio because the user share and balance in the active sub vault would no longer be in balance. If any users unsubscribe during step 2n later on, it further complicates the situation, making it increasingly challenging to trace the original deposited amounts.
As the user share and balance in the active sub vault are no longer at a 1:1 ratio, each round of step 8n redistributes the existing losses or gains from the active sub vault to users moving from the warmup sub vault. Additionally, each refund_active action during step 12n transfers unfilled user shares from the active sub vault back to the warmup sub vault. This complexity compounds with each round, which is why, in the event of calculation errors, new deposits from users who haven’t undergone the in-the-money phase can result in unexpected losses.
The issue with this operation stems from the split transactions needing to be atomic. In order to solve this problem, we implemented a concept similar to an on-chain mutex where we temporarily halt user transactions during operations of the aforementioned steps. The consequences of this is that operating takes a considerable amount of time, causing delays in our auction schedule and requiring more crankers.
Our product isn’t ideally suited for entirely relying on dynamic fields. Although vectors may appear to be a potential solution to this issue, Sui imposes a cap on the capacity of vectors, restricting them to 256,000 bytes. To put this in perspective, let’s consider Typus, which allocates 100 bytes of user data to each element. In this scenario, the utmost capacity of a single vector is limited to accommodating 2,560 users. Any attempt to exceed this threshold will lead to a transaction failure. This effectively rules out the use of vectors.
To recap, the two limitations we’ve faced from the current Sui framework are:
Enter the concept of big vector, a solution designed to address both of these limitations simultaneously. The fundamental idea behind big vector is to employ dynamic fields to store multiple vectors, akin to breaking a substantial vector into numerous smaller slices. If we can store the data of 2,000 users in a single vector slice, and a single dynamic field can access up to 1,000 objects at once, the maximum capacity expands to accommodate 2,000,000 users within a single transaction.
Big vector, in essence, shatters the upper limit imposed by vectors by merging dynamic fields and vectors, while simultaneously relaxing the access limitation of 1,000 objects within a dynamic field. This results in an increase in the number of elements that can be accessed within a single transaction, effectively enhancing scalability.
The rationale behind our desire to integrate big vector into the Sui framework lies in our belief that when accessing the same dynamic field, gas fees should not surge with each access, and there should be a more efficient method for memory allocation.
We replicated the vault settlement gas fee experiment on testnet using our big vector framework. When executing a single round for a vault comprising 45,000 users, the associated gas fees amounted to 7.1 SUI. Considering our current vaults, this significantly reduces our monthly operational settlement gas fee expenses to approximately 1,690 SUI. This is a substantial decrease from the previous range of 7,140 to 16,660 SUI in V1, all while accommodating more users concurrently.
V1 mainnet gas fee 20k users in the vault -> 30 — 70 SUI / round
V2 testnet gas fee 45k users in the vault -> 7.1 SUI / round
A significant factor contributing to the reduction in fees in our V2 is the change in data access. Unlike the past, where each user had their own dynamic field, we now place vectors within dynamic fields. This results in a substantial decrease in dynamic field access frequency. As a result, what remains are the regular, standard data access gas costs.
V2 testnet gas fee txns
update_price + activate: 3.80566692 SUI https://suiexplorer.com/txblock/8mp6Jug43CQd8Y4Xk5K5gmApxVt2cz91a8qv8MEbZc8Q?network=testnet
new_auction: 0.019801108 SUI
https://suiexplorer.com/txblock/Du2Dvbnc3nN3h51t16moEGnjBDBvRcWnQbpGDnS6hJ2s?network=testnet
delivery: 1.8085723 SUI
https://suiexplorer.com/txblock/7SHDY4JLBJqpGkvqP78F83JJqPUfh4L8ugG6rzrUth6c?network=testnet
recoup: 2.39032962 SUI
https://suiexplorer.com/txblock/BmLXPeoL5U1TeaVyhMXDjeUnUiL53vb1oAMocG5tR7vV?network=testnet
settle: 0.001376352 SUI
https://suiexplorer.com/txblock/CUiKwKbMpXUfh3vonQL1zJ9nxGiYSokGE2G4dp2r8Ts3?network=testnet
By drastically reducing the operating cost, we are now able to diversify our product offerings. This expansion encompasses a broader range of underlying assets, strike prices, and expirations. The advantage of consolidating the operation into a single transaction is that it minimizes the risk of calculation discrepancies that could arise from executing multiple transactions. Consequently, we can introduce short-term duration vaults, such as 1-hour, 5-minute, and 1-minute options vaults, all while upholding settlement accuracy.
We recognize that dynamic fields serve as a data store access, but we’d like to emphasize the restrictions they impose on scalability and the risks associated with complex code. Some may argue that these can be mitigated by implementing limitations and optimizing data structures, but the drawback is slower execution speed and higher costs. Given this, it raises the question: are there better solutions out there?
Big vector presents itself as a solution for time-sensitive applications that require single transaction operations, as well as data-access-heavy applications that can’t solely rely on dynamic fields. This approach not only eradicates the need to compromise on your code to fit within the 1,000 object limit but also significantly reduces the associated gas fees.
Our goal is to open a discussion for integrating big vector into the Sui framework, offering a more efficient approach to memory allocation. We believe that when users access the same dynamic field, gas fees shouldn’t increase with each access.
As liquidity continues to accumulate on-chain and Sui’s TVL experiences exponential growth, we anticipate an influx of new users and applications. There is a technological imperative for a framework that can provide hyper-scalability within a single transaction while keeping costs at a minimum. We believe there should be conversations around implementing a new approach as a solution for all builders on Sui.
Written by six0hfour from the Typus team.
⭑ If you liked this content, found it helpful, or would like to start a discussion with us, all our socials are linked here:
https://link3.to/typusfinance
We’ll be releasing more original content soon, in the meantime, check out Typus and try it out yourselves!
https://typus.finance/
References:
Typus Devs
https://github.com/MystenLabs/sui/blob/main/crates/sui-protocol-config/src/lib.rs#L1164
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。