-
Notifications
You must be signed in to change notification settings - Fork 45
Polygon support #330
Polygon support #330
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,118 @@ | ||
const { buildScenarios } = require('../util/scenario'); | ||
const { getNotice } = require('../util/substrate'); | ||
|
||
let now = Date.now(); | ||
|
||
let lock_scen_info = { | ||
tokens: [ | ||
{ token: 'usdc', balances: { ashley: 1000 } }, | ||
{ token: 'maticZrx', balances: { darlene: 1000 } } | ||
{ token: 'maticZrx', balances: { darlene: 1000000 } }, | ||
{ token: 'zrx', balances: { bert: 1000000 } }, | ||
{ token: 'comp' } | ||
], | ||
validators: ['alice', 'bob'], | ||
actors: ['ashley', 'darlene'], | ||
actors: ['ashley', 'bert', 'chuck', 'darlene', 'edward'], | ||
chain_opts: { | ||
matic: { | ||
name: 'matic', | ||
provider: 'ganache', // [env=PROVIDER] | ||
provider: 'ganache', | ||
ganache: { | ||
opts: {}, | ||
web3_port: null | ||
}, | ||
}, | ||
}, | ||
native: true, // for log messages - removes wasm:stripped - no need for wasm no forkless upgrade testing here | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is more for freeze time here. You should have log messages so long as you run |
||
freeze_time: now, | ||
initial_yield: 300, | ||
initial_yield_start_ms: now | ||
}; | ||
|
||
buildScenarios('Matic', lock_scen_info, [ | ||
{ | ||
skip: true, // TODO FIX SCEN | ||
name: 'Matic', | ||
scenario: async ({ darlene, maticZrx }) => { | ||
await darlene.lock(1000, maticZrx); | ||
name: 'Matic Lock', | ||
scenario: async ({ashley, usdc, darlene, maticZrx }) => { | ||
// Lock on Polygon | ||
let balance, liquidity; | ||
await darlene.lock(100, maticZrx); | ||
balance = await darlene.balanceForToken(maticZrx); | ||
let darleneLiquidity = await darlene.liquidity(); | ||
expect(balance).toEqual(100); | ||
expect(darleneLiquidity).toBeGreaterThan(0); | ||
|
||
// lock on ethereum | ||
await ashley.lock(1000, usdc); | ||
balance = await ashley.balanceForToken(usdc); | ||
liquidity = await ashley.liquidity(); | ||
expect(balance).toEqual(1000); | ||
expect(liquidity).toBeGreaterThan(0); | ||
|
||
// lock on polygon again | ||
await darlene.lock(100, maticZrx); | ||
balance = await darlene.balanceForToken(maticZrx); | ||
liquidity = await darlene.liquidity(); | ||
expect(balance).toEqual(200); // double the asset balance (no interest, 0 utilization) | ||
expect(liquidity).toEqual(2*darleneLiquidity); // liquidity must have gone up | ||
} | ||
}, | ||
{ | ||
name: 'Collateral Borrowed Interest Lump Sum', | ||
scenario: async ({ darlene, chuck, cash, chain, usdc, maticZrx}) => { | ||
// await prices.postPrices(); | ||
let balance, liquidity; | ||
await chain.setFixedRate(usdc, 500); // 5% APY fixed | ||
await darlene.lock(10000, maticZrx); | ||
balance = await darlene.balanceForToken(maticZrx); | ||
let liquidity1 = await darlene.liquidity(); | ||
expect(balance).toEqual(10000); | ||
expect(liquidity1).toBeGreaterThan(0); | ||
// now we know everything is in order, make the transfer, let's say half our liquidity worth | ||
await darlene.transfer(1000, usdc, chuck); | ||
expect(await darlene.chainBalance(usdc)).toEqual(-1000); | ||
expect(await chuck.chainBalance(usdc)).toEqual(1000); | ||
expect(await darlene.chainBalance(cash)).toBeCloseTo(-0.01, 2); // 1¢ transfer fee | ||
expect(await chuck.chainBalance(cash)).toEqual(0); | ||
await chain.accelerateTime({years: 1}); | ||
expect(await darlene.chainBalance(usdc)).toEqual(-1000); | ||
expect(await chuck.chainBalance(usdc)).toEqual(1000); | ||
expect(await darlene.chainBalance(cash)).toBeCloseTo(-51.53272669767585, 3); // -50 * Math.exp(0.03) - 0.01 | ||
expect(await chuck.chainBalance(cash)).toBeCloseTo(51.52272669767585, 3); // 50 * Math.exp(0.03) | ||
} | ||
}, | ||
{ | ||
name: "Extract Collateral", | ||
scenario: async ({ darlene, maticZrx, chain, maticStarport }) => { | ||
let assetInfo = await maticZrx.getAssetInfo(); | ||
|
||
let balance, liquidity; | ||
// start with 1,000,000 | ||
// lock 10,000 | ||
// on matic = 990,000 | ||
// on gateway = 10,000 | ||
await darlene.lock(10000, maticZrx); | ||
balance = await darlene.balanceForToken(maticZrx); | ||
expect(balance).toEqual(10000); // gateway balance not yet debited | ||
expect(await darlene.tokenBalance(maticZrx)).toEqual(990000); // matic balance not yet credited | ||
liquidity = await darlene.liquidity(); | ||
expect(liquidity).toBeGreaterThan(0); | ||
|
||
// request extract 50 maticZrx | ||
let extract = await darlene.extract(50, maticZrx); | ||
let notice = getNotice(extract); | ||
let signatures = await chain.getNoticeSignatures(notice); | ||
|
||
// before we submit - query the balances to ensure they are as expected | ||
balance = await darlene.balanceForToken(maticZrx); | ||
expect(balance).toEqual(9950); // gateway balance debited | ||
expect(await darlene.tokenBalance(maticZrx)).toEqual(990000); // matic balance not yet credited | ||
// now invoke the notice! | ||
await maticStarport.invoke(notice, signatures); | ||
// balances are updated everywhere, should now be | ||
// on matic = 990,050 | ||
// on gateway = 9,950 | ||
balance = await darlene.balanceForToken(maticZrx); | ||
expect(balance).toEqual(9950); // gateway balance debited | ||
expect(await darlene.tokenBalance(maticZrx)).toEqual(990050); // matic balance now credited | ||
} | ||
}, | ||
]); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ class Actor { | |
} | ||
|
||
chain() { | ||
return this.ctx.chains.find(this.chainName()); | ||
return this.ctx.chains.find(this.chainName); | ||
} | ||
|
||
show() { | ||
|
@@ -32,11 +32,13 @@ class Actor { | |
} | ||
|
||
toChainAccount() { | ||
return { Eth: this.ethAddress() }; | ||
const returnValue = {}; | ||
returnValue[this.chain().nameAsPascalCase()] = this.ethAddress(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this might be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think for now having ethAddress is ok but we will ultimately change a lot of this code when flow comes into play. To be honest, I'm a little bit intimidated refactoring something as pervasive as that could be in js without the help of a compiler There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, we could use TypeScript, but it's a huge burden for tests since it takes a lot more time to write and tests are pretty one-offy. We could technically upgrade if we think it would help us. |
||
return returnValue; | ||
} | ||
|
||
toTrxArg() { | ||
return `Eth:${this.ethAddress()}`; | ||
return `${this.chain().nameAsPascalCase()}:${this.ethAddress()}`; | ||
} | ||
|
||
declareInfo() { | ||
|
@@ -59,14 +61,16 @@ class Actor { | |
} | ||
|
||
async sign(data) { | ||
return await this.ctx.eth.sign(data, this); | ||
return await this.chain().sign(data, this); | ||
} | ||
|
||
async signWithNonce(data) { | ||
let currentNonce = await this.nonce(); | ||
let signature = await this.sign(`${currentNonce}:${data}`); | ||
const signatureData = {}; | ||
signatureData[this.chain().nameAsPascalCase()] = [this.ethAddress(), signature]; | ||
|
||
return [ { Eth: [ this.ethAddress(), signature ] }, currentNonce ]; | ||
return [ signatureData, currentNonce ]; | ||
} | ||
|
||
async runTrxRequest(trxReq) { | ||
|
@@ -77,7 +81,7 @@ class Actor { | |
} | ||
|
||
async ethBalance() { | ||
return await this.ctx.eth.ethBalance(this); | ||
return await this.chain().ethBalance(this); | ||
} | ||
|
||
async tokenBalance(tokenLookup) { | ||
|
@@ -138,19 +142,28 @@ class Actor { | |
return Number(balance) / 1e6; | ||
} | ||
|
||
async liquidityForToken(token) { | ||
async balanceForToken(token) { | ||
let assetBalance = await this.ctx.getApi().query.cash.assetBalances(token.toChainAsset(), this.toChainAccount()); | ||
if (assetBalance === 0) { | ||
return 0; | ||
} | ||
|
||
return token.toTokenAmount(assetBalance.toBigInt()); | ||
} | ||
|
||
async liquidityForToken(token) { | ||
let assetBalance = await this.balanceForToken(token); | ||
let price = await token.getPrice(); | ||
let liquidityFactor = await token.getLiquidityFactor(); | ||
|
||
if (assetBalance == 0) { | ||
if (assetBalance === 0) { | ||
return 0; | ||
} else if (assetBalance > 0) { | ||
// AssetBalance • LiquidityFactor_Asset • Price_Asset | ||
return token.toTokenAmount(assetBalance.toBigInt()) * price * liquidityFactor; | ||
return assetBalance * price * liquidityFactor; | ||
} else { | ||
// AssetBalance ÷ LiquidityFactor_Asset • Price_Asset | ||
return token.toTokenAmount(assetBalance.toBigInt()) * price / liquidityFactor; | ||
return assetBalance * price / liquidityFactor; | ||
} | ||
} | ||
|
||
|
@@ -167,10 +180,12 @@ class Actor { | |
}; | ||
|
||
return await this.declare("lock", [amount, asset], async () => { | ||
let tx = await asset.chain().starport.lock(this, amount, asset); | ||
const chain = asset.chain(); | ||
let tx = await chain.starport.lock(this, amount, asset); | ||
|
||
let event; | ||
if (opts.awaitEvent) { | ||
event = await this.ctx.chain.waitForEthProcessEvent('cash', asset.lockEventName()); | ||
event = await this.ctx.chain.waitForL1ProcessEvent(chain, 'cash', asset.lockEventName()); | ||
} | ||
return { | ||
event, | ||
|
@@ -284,6 +299,10 @@ function actorInfoMap(keyring) { | |
darlene: { | ||
chainName: 'matic', | ||
key_uri: '//Darlene' | ||
}, | ||
edward: { | ||
chainName: 'matic', | ||
key_uri: '//Edward' | ||
} | ||
}; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need native here, but I'm not strictly against it, either. Probably should just use the default though, nah?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was before we were doing wasm logging was impossible to tell what was going on, also is native faster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH, it doesn't really matter here. Native is when you're asking for a different genesis native, e.g. running m14's native build. It's irrelevant here, but also, again, if we wanted to change it, we should change the default, not one one-off scen.