Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
268a3f2
Modified Exchange.sol to accepted a registry identifier instead of an…
Tjudice Jun 29, 2021
b379c50
Readded deprecated setStableToken() function
Tjudice Jun 30, 2021
313fcc8
Fixed lint errors
Tjudice Jun 30, 2021
419cef2
Added more TS fixes to test
Tjudice Jun 30, 2021
1e6eae0
More initialization args fixes
Tjudice Jun 30, 2021
d7b5670
Fix to value never read
Tjudice Jun 30, 2021
dd3e1ce
More changes to fix tests in exchange.ts
Tjudice Jul 1, 2021
8f5b2f8
cleanup
yorhodes Jul 6, 2021
c20ebb5
Removed .only so test cases all run
Tjudice Jul 6, 2021
d37f894
Fixed 'should return the correct amount of buy and sell token' test c…
Tjudice Jul 7, 2021
5fda30e
Test
Tjudice Jul 7, 2021
ee83902
Added ExchangeTest.sol file to allow for updating buckets in an effic…
Tjudice Jul 8, 2021
a0df5e6
Fixes
Tjudice Jul 9, 2021
687fd64
cleanup
yorhodes Jul 12, 2021
87e2668
Changes to updateBucketsIfNeccesary() modifier
Tjudice Jul 13, 2021
4c91736
Fixed integration tests bug
Tjudice Jul 14, 2021
bef40e1
updated versions
Tjudice Jul 28, 2021
542013a
Merge branch 'master' into tjudice/exchangeFix
yorhodes Oct 29, 2021
4d576db
Add stabletoken activation to exchange
yorhodes Oct 29, 2021
b24ccf1
Use activateStable in tests and migrations
yorhodes Oct 29, 2021
3732256
Bump exchange version
yorhodes Oct 29, 2021
a9320fd
Activate stable in integration tests
yorhodes Oct 29, 2021
e4c8f4a
Address pr comments
yorhodes Nov 1, 2021
353fbfe
Merge branch 'master' into tjudice/exchangeFix
m-chrzan Jan 12, 2022
5c6aaa7
Update StableTokenBRL.sol
martinvol Jan 12, 2022
8a02089
Updated build TAG on CI
martinvol Jan 12, 2022
33e8b19
Merge branch 'tjudice/exchangeFix' of github.com:celo-org/celo-monore…
martinvol Jan 12, 2022
aadec59
Fixed Exchange version
martinvol Jan 12, 2022
3c6b9c0
revert change tag
martinvol Jan 12, 2022
29b663c
Added activation to cREAL
martinvol Jan 13, 2022
54bdf05
Changed contracts
martinvol Jan 13, 2022
cae8504
don't change BRL versio
martinvol Jan 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions packages/protocol/contracts/stability/Exchange.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ contract Exchange is
uint256 public updateFrequency;
uint256 public minimumReports;

bytes32 public stableTokenRegistryId;

modifier updateBucketsIfNecessary() {
_updateBucketsIfNecessary();
_;
Expand All @@ -64,7 +66,7 @@ contract Exchange is
* @return The storage, major, minor, and patch version of the contract.
*/
function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
return (1, 1, 1, 0);
return (1, 2, 0, 0);
}

/**
Expand All @@ -76,30 +78,39 @@ contract Exchange is
/**
* @notice Used in place of the constructor to allow the contract to be upgradable via proxy.
* @param registryAddress The address of the registry core smart contract.
* @param stableToken Address of the stable token
* @param _spread Spread charged on exchanges
* @param _reserveFraction Fraction to commit to the gold bucket
* @param _updateFrequency The time period that needs to elapse between bucket
* updates
* @param _minimumReports The minimum number of fresh reports that need to be
* present in the oracle to update buckets
* commit to the gold bucket
* @param stableTokenIdentifier String identifier of stabletoken in registry
*/
function initialize(
address registryAddress,
address stableToken,
string calldata stableTokenIdentifier,
uint256 _spread,
uint256 _reserveFraction,
uint256 _updateFrequency,
uint256 _minimumReports
) external initializer {
_transferOwnership(msg.sender);
setRegistry(registryAddress);
setStableToken(stableToken);
stableTokenRegistryId = keccak256(abi.encodePacked(stableTokenIdentifier));
setSpread(_spread);
setReserveFraction(_reserveFraction);
setUpdateFrequency(_updateFrequency);
setMinimumReports(_minimumReports);
}

/**
* @notice Ensures stable token address is set in storage and initializes buckets.
* @dev Will revert if stable token is not registered or does not have oracle reports.
*/
function activateStable() external onlyOwner {
require(stable == address(0), "StableToken address already activated");
_setStableToken(registry.getAddressForOrDie(stableTokenRegistryId));
_updateBucketsIfNecessary();
}

Expand Down Expand Up @@ -276,8 +287,7 @@ contract Exchange is
* @param newStableToken The new address for Stable Token
*/
function setStableToken(address newStableToken) public onlyOwner {
stable = newStableToken;
emit StableTokenSet(newStableToken);
_setStableToken(newStableToken);
}

/**
Expand All @@ -299,6 +309,11 @@ contract Exchange is
emit ReserveFractionSet(newReserveFraction);
}

function _setStableToken(address newStableToken) internal {
stable = newStableToken;
emit StableTokenSet(newStableToken);
}

/**
* @notice Returns the buy token and sell token bucket sizes, in order. The ratio of
* the two also represents the exchange rate between the two.
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/stability/ExchangeEUR.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ contract ExchangeEUR is Exchange {
* @return The storage, major, minor, and patch version of the contract.
*/
function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
return (1, 1, 0, 0);
return (1, 2, 0, 0);
}
}
9 changes: 3 additions & 6 deletions packages/protocol/migrations/10_0_exchange_USD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@ import {
} from '@celo/protocol/lib/web3-utils'
import { config } from '@celo/protocol/migrationsConfig'
import { toFixed } from '@celo/utils/lib/fixidity'
import { ExchangeInstance, FreezerInstance, StableTokenInstance } from 'types'
import { ExchangeInstance, FreezerInstance } from 'types'

const initializeArgs = async (): Promise<any[]> => {
const stableToken: StableTokenInstance = await getDeployedProxiedContract<StableTokenInstance>(
'StableToken',
artifacts
)
return [
config.registry.predeployedProxyAddress,
stableToken.address,
CeloContractName.StableToken,
toFixed(config.exchange.spread).toString(),
toFixed(config.exchange.reserveFraction).toString(),
config.exchange.updateFrequency,
Expand All @@ -37,5 +33,6 @@ module.exports = deploymentForCoreContract<ExchangeInstance>(
)
await freezer.freeze(exchange.address)
}
await exchange.activateStable()
}
)
14 changes: 3 additions & 11 deletions packages/protocol/migrations/10_1_exchange_EUR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,12 @@ import {
} from '@celo/protocol/lib/web3-utils'
import { config } from '@celo/protocol/migrationsConfig'
import { toFixed } from '@celo/utils/lib/fixidity'
import {
ExchangeEURInstance,
FreezerInstance,
ReserveInstance,
StableTokenEURInstance,
} from 'types'
import { ExchangeEURInstance, FreezerInstance, ReserveInstance } from 'types'

const initializeArgs = async (): Promise<any[]> => {
const stableTokenEUR: StableTokenEURInstance = await getDeployedProxiedContract<StableTokenEURInstance>(
'StableTokenEUR',
artifacts
)
return [
config.registry.predeployedProxyAddress,
stableTokenEUR.address,
CeloContractName.StableTokenEUR,
toFixed(config.exchange.spread).toString(),
toFixed(config.exchange.reserveFraction).toString(),
config.exchange.updateFrequency,
Expand Down Expand Up @@ -49,5 +40,6 @@ module.exports = deploymentForCoreContract<ExchangeEURInstance>(
)
// cUSD doesn't need to be added as it is currently harcoded in Reserve.sol
await reserve.addExchangeSpender(exchange.address)
await exchange.activateStable()
}
)
14 changes: 3 additions & 11 deletions packages/protocol/migrations/10_2_exchange_BRL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,12 @@ import {
} from '@celo/protocol/lib/web3-utils'
import { config } from '@celo/protocol/migrationsConfig'
import { toFixed } from '@celo/utils/lib/fixidity'
import {
ExchangeBRLInstance,
FreezerInstance,
ReserveInstance,
StableTokenBRLInstance,
} from 'types'
import { ExchangeBRLInstance, FreezerInstance, ReserveInstance } from 'types'

const initializeArgs = async (): Promise<any[]> => {
const stableTokenBRL: StableTokenBRLInstance = await getDeployedProxiedContract<StableTokenBRLInstance>(
'StableTokenBRL',
artifacts
)
return [
config.registry.predeployedProxyAddress,
stableTokenBRL.address,
CeloContractName.StableTokenBRL,
toFixed(config.exchange.spread).toString(),
toFixed(config.exchange.reserveFraction).toString(),
config.exchange.updateFrequency,
Expand Down Expand Up @@ -49,5 +40,6 @@ module.exports = deploymentForCoreContract<ExchangeBRLInstance>(
)
// cUSD doesn't need to be added as it is currently harcoded in Reserve.sol
await reserve.addExchangeSpender(exchange.address)
await exchange.activateStable()
}
)
8 changes: 4 additions & 4 deletions packages/protocol/test/common/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ contract('Integration: Adding StableToken', (accounts: string[]) => {
)
await exchangeAbc.initialize(
registry.address,
stableTokenAbc.address,
'StableTokenABC',
'5000000000000000000000', // spread, matches mainnet for cUSD and cEUR
'1300000000000000000000', // reserveFraction, matches mainnet for cEUR
'300', // updateFrequency, matches mainnet for cUSD and cEUR
Expand All @@ -638,9 +638,6 @@ contract('Integration: Adding StableToken', (accounts: string[]) => {
it(`should be impossible to sell CELO`, async () => {
await goldToken.approve(exchangeAbc.address, sellAmount)
await assertRevert(exchangeAbc.sell(sellAmount, minBuyAmount, true))
// This last case is not relevant, but the test is meant to warn in case the behavior ever changes
await goldToken.approve(exchangeAbc.address, sellAmount)
await exchangeAbc.sell(sellAmount, 0, true)
})

it(`should be impossible to sell stable token`, async () => {
Expand Down Expand Up @@ -691,6 +688,9 @@ contract('Integration: Adding StableToken', (accounts: string[]) => {
await reserve.addExchangeSpender(exchangeAbc.address)
await freezer.unfreeze(stableTokenAbc.address)
await freezer.unfreeze(exchangeAbc.address)

// activate stable during mento-activation proposal
await exchangeAbc.activateStable()
// Fee currency can't be tested here, but keep this line for reference
await feeCurrencyWhitelist.addToken(stableTokenAbc.address)
})
Expand Down
66 changes: 63 additions & 3 deletions packages/protocol/test/stability/exchange.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { NULL_ADDRESS } from '@celo/base'
import { CeloContractName } from '@celo/protocol/lib/registry-utils'
import {
addressMinedLatestBlock,
Expand All @@ -24,6 +25,7 @@ import {
StableTokenContract,
StableTokenInstance,
} from 'types'
import { keccak256 } from 'web3-utils'
import { SECONDS_IN_A_WEEK } from '../constants'

const Exchange: ExchangeContract = artifacts.require('Exchange')
Expand Down Expand Up @@ -126,7 +128,7 @@ contract('Exchange', (accounts: string[]) => {
SECONDS_IN_A_WEEK,
[],
[],
'Exchange' // USD
CeloContractName.Exchange // USD
)

mockSortedOracles = await MockSortedOracles.new()
Expand All @@ -140,12 +142,14 @@ contract('Exchange', (accounts: string[]) => {
exchange = await Exchange.new(true)
await exchange.initialize(
registry.address,
stableToken.address,
CeloContractName.StableToken,
spread,
reserveFraction,
updateFrequency,
minimumReports
)

await registry.setAddressFor(CeloContractName.StableToken, stableToken.address)
await registry.setAddressFor(CeloContractName.Exchange, exchange.address)
})

Expand All @@ -155,11 +159,16 @@ contract('Exchange', (accounts: string[]) => {
assert.equal(expectedOwner, accounts[0])
})

it('should set stable token identfier', async () => {
const identifier = await exchange.stableTokenRegistryId()
assert.equal(identifier, keccak256(CeloContractName.StableToken))
})

it('should not be callable again', async () => {
await assertRevert(
exchange.initialize(
registry.address,
stableToken.address,
CeloContractName.StableToken,
spread,
reserveFraction,
updateFrequency,
Expand All @@ -169,6 +178,36 @@ contract('Exchange', (accounts: string[]) => {
})
})

describe('#activateStable', () => {
it('should emit a StableTokenSet event', async () => {
const tx = await exchange.activateStable()
assertLogMatches2(tx.logs[0], {
event: 'StableTokenSet',
args: {
stable: stableToken.address,
},
})
})

it('should set the stable storage address', async () => {
const stableBefore = await exchange.stable()
assert.equal(stableBefore, NULL_ADDRESS)
await exchange.activateStable()
const stableAfter = await exchange.stable()
assert.equal(stableAfter, stableToken.address)
})

it('should not allow a non-owner to activate', async () => {
const nonOwner = accounts[1]
await assertRevert(exchange.activateStable({ from: nonOwner }))
})

it('should not be callable again', async () => {
await exchange.activateStable()
await assertRevert(exchange.activateStable())
})
})

describe('#setUpdateFrequency', () => {
const newUpdateFrequency = new BigNumber(60 * 30)

Expand Down Expand Up @@ -318,6 +357,10 @@ contract('Exchange', (accounts: string[]) => {
})

describe('#getBuyAndSellBuckets', () => {
beforeEach(async () => {
await exchange.activateStable()
})

it('should return the correct amount of buy and sell token', async () => {
const [buyBucketSize, sellBucketSize] = await exchange.getBuyAndSellBuckets(true)
assertEqualBN(sellBucketSize, initialGoldBucket)
Expand Down Expand Up @@ -355,6 +398,7 @@ contract('Exchange', (accounts: string[]) => {

it(`should return the same value if updateFrequency seconds haven't passed yet`, async () => {
await mockSortedOracles.setMedianTimestampToNow(stableToken.address)

const [buyBucketSize, sellBucketSize] = await exchange.getBuyAndSellBuckets(true)

assertEqualBN(sellBucketSize, initialGoldBucket)
Expand All @@ -374,6 +418,10 @@ contract('Exchange', (accounts: string[]) => {
})

describe('#getBuyTokenAmount', () => {
beforeEach(async () => {
await exchange.activateStable()
})

it('should return the correct amount of buyToken', async () => {
const amount = 10
const buyAmount = await exchange.getBuyTokenAmount(amount, true)
Expand All @@ -389,6 +437,10 @@ contract('Exchange', (accounts: string[]) => {
})

describe('#getSellTokenAmount', () => {
beforeEach(async () => {
await exchange.activateStable()
})

it('should return the correct amount of sellToken', async () => {
const buyAmount = 10
const sellAmount = await exchange.getSellTokenAmount(buyAmount, true)
Expand All @@ -409,6 +461,10 @@ contract('Exchange', (accounts: string[]) => {

for (const sellFunctionName of sellFunctionNames) {
describe(`#${sellFunctionName}`, () => {
beforeEach(async () => {
await exchange.activateStable()
})

const user = accounts[1]

// This test is run for both the `sell` and `exchange` functions
Expand Down Expand Up @@ -924,6 +980,10 @@ contract('Exchange', (accounts: string[]) => {
}

describe('#buy', () => {
beforeEach(async () => {
await exchange.activateStable()
})

const user = accounts[1]

describe('when buying stable with gold', () => {
Expand Down