SIP-46: Address Resolver Gas Improvements

Author
Discussions-To<https://discordapp.com/invite/AEdUHzt>
StatusImplemented
Created2020-03-02

Simple Summary

Cache addresses from resolver inside contracts to reduce gas usage.

Abstract

Ensure that each contract relying on addresses from the AddressResolver caches its own copy of these addresses, thereby reducing the gas usage for users when executing regular transactions like issue, burn, claim and exchange. The cache however must be refreshed on each and every deployment.

Motivation

In our Achernar release (v2.19.8), we introduced SIP-43 - an address lookup contract into the FeePool, Synthetix, Exchanger, Issuer and all Synth contracts, among others. The impact to gas on common user functions like FeePool.claim, Synthetix.exchange and Synthetix.issueSynths was signficant.

Prior to Achernar

Contract Function Gas Used
FeePool claimFees 322,641
Synthetix burnSynths 352,748
Synthetix exchange 226,041
Synthetix issueMaxSynths 342,547
Synthetix issueSynths 361,070

from https://github.com/Synthetixio/synthetix/runs/353850454

After Achernar

Contract Function Gas Used Diff %
FeePool claimFees 497,550 +174,909 +54%
Synthetix burnSynths 547,257 +193,145 +55%
Synthetix exchange 565,260 +339,218 +150%
Synthetix issueMaxSynths 503,953 +161,406 +47%
Synthetix issueSynths 531,401 +168,223 +46%

from https://github.com/Synthetixio/synthetix/runs/457383033

The biggest impact is to exchange() however that was primarily due to SIP-37 (Fee Reclamation) that was also released in Achernar.

By caching the various required addresses, we can reduce these down and not worry about having to write code in each function to limit how often we lookup the addresses required.

Specification

  1. Introduce a local mapping(bytes32 => address) cache into MixinResolver - the functionality included in all contracts that need to communicate via the address resolver
  2. Ensure MixinResolver is instantiated with a list of bytes32 addresses that the contract needs to know about
  3. Expose a function in MixinResolver.setResolverAndSyncCache() to sync the cache. This is to be called each deployment whenever any new contracts are added.

Preliminary investigations after Caching and other improvements (such as SIP-41):

Contract Function Gas Used Diff from pre-Achenar %
FeePool claimFees 422,852 +100,211 +24%
Synthetix burnSynths 329,877 -22,871 -7%
Synthetix exchange 473,954 +247,913 +110%
Synthetix issueMaxSynths 437,013 +94,466 +28%
Synthetix issueSynths 394,636 +33,566 +9%

from https://github.com/Synthetixio/synthetix/pull/434/checks?check_run_id=480906529

Rationale

  1. A local mapping in each MixinResolver will prevent unnecssary CALL opcodes from being used (approximately 1518 gas)
  2. Having the list of required address names in each MixinResolver will allow automated checks each deployment to know what needs updating in the AddressResolver
  3. After each deployment, determine which MixinResolver contracts need to be resynced based on the list in #2 above

Test Cases

https://github.com/Synthetixio/synthetix/blob/resolver-gas-improvements/test/contracts/MixinResolver.js

https://github.com/Synthetixio/synthetix/blob/resolver-gas-improvements/test/publish/index.js#L944-L1073

Implementation

@Synthetixio/synthetix#434

Copyright and related rights waived via CC0.