diff --git a/migrations/2023_09_18_amp_keys/01_factory_v2_data_tx.json b/migrations/2023_09_18_amp_keys/01_factory_v2_data_tx.json new file mode 100644 index 000000000..abf4114ee --- /dev/null +++ b/migrations/2023_09_18_amp_keys/01_factory_v2_data_tx.json @@ -0,0 +1,108 @@ +{ + "type": 12, + "fee": 500000, + "feeAssetId": null, + "version": 2, + "senderPublicKey": "HBWgh7DKPyzCnEXKJAJ5dKQ3jmPtMhGD78tt6jRdkV61", + "data": [ + { + "key": "%s%s__amp__3P8KMyAJCPWNcyedqrmymxaeWonvmkhGauz", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__changeAmpLastCall__3P8KMyAJCPWNcyedqrmymxaeWonvmkhGauz", + "type": "integer", + "value": 3622973 + }, + { + "key": "%s%s__amp__3PC3HtupBxBmy4WtZf1Tym1vrxg9MwbZRK1", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__changeAmpLastCall__3PC3HtupBxBmy4WtZf1Tym1vrxg9MwbZRK1", + "type": "integer", + "value": 3622973 + }, + { + "key": "%s%s__amp__3P5hjCSDFRGabd7VN74AVPiKNqgAHm8JAbD", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__changeAmpLastCall__3P5hjCSDFRGabd7VN74AVPiKNqgAHm8JAbD", + "type": "integer", + "value": 3622973 + }, + { + "key": "%s%s__amp__3P4Dn8Ghz4QDH5SAL4xQi6cW2FhuKq6gnyC", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__changeAmpLastCall__3P4Dn8Ghz4QDH5SAL4xQi6cW2FhuKq6gnyC", + "type": "integer", + "value": 3622973 + }, + { + "key": "%s%s__amp__3P5VC7EqCZ3BsTuz3QrZFpxZ9VEm5N6WHTb", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3P5muaLnF5EB3QEZTzkPYFDBdMeH8EnNkXs", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3PAqRnZbZ9YQCs2kaq5fUdbvtaKCg9vw7hV", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3PJazesjmprZcXYcFx3LxBux9T7q6qYoEDu", + "value": "50" + }, + { + "key": "%s%s__amp__3P5muaLnF5EB3QEZTzkPYFDBdMeH8EnNkXs", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3PAqRnZbZ9YQCs2kaq5fUdbvtaKCg9vw7hV", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3PJazesjmprZcXYcFx3LxBux9T7q6qYoEDu", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3PDqijReU8yXKFfBGBrRjckzaAp5K8Sywhv", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3PBxqamajfw2cHR2wmv5usiWxBncKLdXVdu", + "type": "string", + "value": "100" + }, + { + "key": "%s%s__amp__3PQ4BZAPz3A8xApagrKHHAaBCipyXyMZfBD", + "type": "string", + "value": "100" + }, + { + "key": "%s%s__amp__3P5V29rzis25fDSpfgGWcDcLY1xxf7MfWRJ", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3P85eCEdGNPJaURRNo3bkrtYm8dhQ2r8tVY", + "type": "string", + "value": "50" + } + ] +} diff --git a/migrations/2023_09_18_amp_keys/02_factory_v2_amp_history_2.json b/migrations/2023_09_18_amp_keys/02_factory_v2_amp_history_2.json new file mode 100644 index 000000000..6449f63d5 --- /dev/null +++ b/migrations/2023_09_18_amp_keys/02_factory_v2_amp_history_2.json @@ -0,0 +1,79 @@ +{ + "type": 12, + "fee": 500000, + "feeAssetId": null, + "version": 2, + "senderPublicKey": "HBWgh7DKPyzCnEXKJAJ5dKQ3jmPtMhGD78tt6jRdkV61", + "data": [ + { + "key": "%s%s%d__amp__3P8KMyAJCPWNcyedqrmymxaeWonvmkhGauz__3622973", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3PC3HtupBxBmy4WtZf1Tym1vrxg9MwbZRK1__3622973", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3P5hjCSDFRGabd7VN74AVPiKNqgAHm8JAbD__3622973", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3P4Dn8Ghz4QDH5SAL4xQi6cW2FhuKq6gnyC__3622973", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3P5VC7EqCZ3BsTuz3QrZFpxZ9VEm5N6WHTb__3034384", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3P5muaLnF5EB3QEZTzkPYFDBdMeH8EnNkXs__3131379", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3PAqRnZbZ9YQCs2kaq5fUdbvtaKCg9vw7hV__3131347", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3PJazesjmprZcXYcFx3LxBux9T7q6qYoEDu__3131318", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3PDqijReU8yXKFfBGBrRjckzaAp5K8Sywhv__3594323", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3PBxqamajfw2cHR2wmv5usiWxBncKLdXVdu__3647513", + "type": "string", + "value": "100" + }, + { + "key": "%s%s%d__amp__3PQ4BZAPz3A8xApagrKHHAaBCipyXyMZfBD__3647513", + "type": "string", + "value": "100" + }, + { + "key": "%s%s%d__amp__3P5V29rzis25fDSpfgGWcDcLY1xxf7MfWRJ__3738380", + "type": "string", + "value": "50" + }, + { + "key": "%s%s%d__amp__3P85eCEdGNPJaURRNo3bkrtYm8dhQ2r8tVY__3800818", + "type": "string", + "value": "50" + }, + { + "key": "%s%s__amp__3P85eCEdGNPJaURRNo3bkrtYm8dhQ2r8tVY", + "type": "string", + "value": "50" + } + ] +} diff --git a/ride/factory_v2.ride b/ride/factory_v2.ride index bc857a08e..d36bddeaa 100644 --- a/ride/factory_v2.ride +++ b/ride/factory_v2.ride @@ -176,6 +176,15 @@ func keyMinBalance(poolAddress: String, assetId: String) func keyMinBalanceDefault(assetId: String) = makeString(["%s%s", "minBalanceDefault", assetId], SEP) +# keyAmplification +func keyAmp(poolAddress: String) + = makeString(["%s%s", "amp", poolAddress], SEP) +func keyAmpHistory(poolAddress: String, heightBlocks: Int) + = makeString(["%s%s%d", "amp", poolAddress, heightBlocks.toString()], SEP) +func keyChangeAmpLastCall(poolAddress: String) + = makeString(["%s%s", "changeAmpLastCall", poolAddress], SEP) +let ampInitial = 50 + func keyAddressWhitelisted(address: Address) = makeString(["%s%s", "whitelisted", address.toString()], SEP) #------------------------ @@ -663,7 +672,9 @@ func activateNewPool(poolAddress: String, amountAssetStr: String, priceAssetStr: StringEntry(keyMappingPoolLPAssetToPoolContractAddress(lpAssetIdStr), poolAddress), StringEntry(keyMappingPoolContractToLPAsset(poolAddress), lpAssetIdStr), IntegerEntry(keyPoolToWeight(poolAddress),poolWeight), - IntegerEntry(keyPoolSpread(poolAddress),defaultSpread) + IntegerEntry(keyPoolSpread(poolAddress),defaultSpread), + StringEntry(keyAmp(poolAddress), ampInitial.toString()), + StringEntry(keyAmpHistory(poolAddress, height), ampInitial.toString()) ] , lpAssetIdStr ) @@ -864,6 +875,36 @@ func onVerificationLoss(assetId: String) = { (nil, unit) } +@Callable(i) +func changeAmp(poolAddress: String) = { + let delay = keyChangeAmpDelay(poolAddress).getIntegerValue() + let delta = keyChangeAmpDelta(poolAddress).getIntegerValue() + let target = keyChangeAmpTarget(poolAddress).getIntegerValue() + + let curAmp = keyAmp(poolAddress).getStringValue().parseIntValue() + let newAmpRaw = curAmp + delta + # to not increment/decrement too much + let newAmp = if (delta < 0) then { + if (newAmpRaw < target) then target else newAmpRaw + } else { + if (newAmpRaw > target) then target else newAmpRaw + } + + let lastCall = keyChangeAmpLastCall(poolAddress).getInteger().valueOrElse(0) + let wait = lastCall+delay + + strict checks = [ + height > wait || "try again in few blocks".throwErr(), + curAmp != newAmp || "already reached target".throwErr() + ] + + [ + IntegerEntry(keyChangeAmpLastCall(poolAddress), height), + StringEntry(keyAmp(poolAddress), newAmp.toString()), + StringEntry(keyAmpHistory(poolAddress, height), newAmp.toString()) + ] +} + @Callable(i) func isPoolOneTokenOperationsDisabledREADONLY(poolAddress: String) = { let poolConfig = poolAddress.getPoolConfig() @@ -1028,7 +1069,10 @@ func deletePool(poolContractAddress: String) = { DeleteEntry(keyChangeAmpDelay(poolContractAddress)), DeleteEntry(keyChangeAmpDelta(poolContractAddress)), - DeleteEntry(keyChangeAmpTarget(poolContractAddress)) + DeleteEntry(keyChangeAmpTarget(poolContractAddress)), + + DeleteEntry(keyAmp(poolContractAddress)), + DeleteEntry(keyChangeAmpLastCall(poolContractAddress)) ] } diff --git a/ride/lp_stable.ride b/ride/lp_stable.ride index 88b37557e..e7f3d4acb 100644 --- a/ride/lp_stable.ride +++ b/ride/lp_stable.ride @@ -47,7 +47,6 @@ let big3 = 3.toBigInt() let big4 = 4.toBigInt() let slippage4D = (scale8 - scale8 * 1 / scale8).toBigInt() # 9999999 or error of 0.0000001 let wavesString = "WAVES" -let ampInitial = 50 let Amult = "100" let Dconv = "1" # D convergence @@ -113,9 +112,7 @@ func gau(ua: String, txId: String) = "%s%s%s__G__" + ua + "__" + txId func aa() = {"%s__amountAsset"} func pa() = {"%s__priceAsset"} # keyAmplificator -func amp() = {"%s__amp"} -func keyAmpHistory(heightBlocks: Int) = "%s%d__amp__" + heightBlocks.toString() -func keyChangeAmpLastCall() = "%s__changeAmpLastCall" +func amp() = {["%s%s", "amp", this.toString()].makeString(SEP)} let keyFee = "%s__fee" let fee = this.getInteger(keyFee).valueOrElse(feeDefault) @@ -198,7 +195,7 @@ func isAddressWhitelisted(address: Address) = { fca.getBoolean(keyAddressWhitelisted(address)).valueOrElse(false) } -let A = strf(this, amp()) +let A = strf(fca, amp()) # isGlobalShutdown # check that global shutdown is take place @@ -1620,9 +1617,7 @@ func activate(amtAsStr: String, prAsStr: String) = { if (i.caller.toString() != fca.toString()) then throw("denied") else { ([ StringEntry(aa(),amtAsStr), - StringEntry(pa(),prAsStr), - StringEntry(amp(), ampInitial.toString()), - StringEntry(keyAmpHistory(height), ampInitial.toString()) + StringEntry(pa(),prAsStr) ], "success") } @@ -1730,36 +1725,8 @@ func estimateGetOperationWrapperREADONLY(txId58: String, pmtAsId: String, pmtLpA @Callable(i) func changeAmp() = { - let cfg = fca.invoke("getChangeAmpConfigREADONLY", [this.toString()], []) - let (delay, delta, target) = match cfg { - case list: List[Any] => { - (list[0].exactAs[Int], list[1].exactAs[Int], list[2].exactAs[Int]) - } - case _ => "invalid entry type".throwErr() - } - - let curAmp = amp().getStringValue().parseIntValue() - let newAmpRaw = curAmp + delta - # to not increment/decrement too much - let newAmp = if (delta < 0) then { - if (newAmpRaw < target) then target else newAmpRaw - } else { - if (newAmpRaw > target) then target else newAmpRaw - } - - let lastCall = keyChangeAmpLastCall().getInteger().valueOrElse(0) - let wait = lastCall+delay - - strict checks = [ - height > wait || "try again in few blocks".throwErr(), - curAmp != newAmp || "already reached target".throwErr() - ] - - [ - IntegerEntry(keyChangeAmpLastCall(), height), - StringEntry(amp(), newAmp.toString()), - StringEntry(keyAmpHistory(height), newAmp.toString()) - ] + strict fcaInv = fca.invoke("changeAmp", [this.toString()], []) + nil } @Verifier(tx) diff --git a/test/components/factory_v2/deletePoolByManager.spec.mjs b/test/components/factory_v2/deletePoolByManager.spec.mjs index 3e2e4608e..f8e18a6a0 100644 --- a/test/components/factory_v2/deletePoolByManager.spec.mjs +++ b/test/components/factory_v2/deletePoolByManager.spec.mjs @@ -239,6 +239,14 @@ describe('Factory V2 - deletePool', /** @this {MochaSuiteModified} */() => { key: `%s%s__changeAmpTarget__${poolAddress}`, value: null, }, + { + key: `%s%s__amp__${poolAddress}`, + value: null, + }, + { + key: `%s%s__changeAmpLastCall__${poolAddress}`, + value: null, + }, ]); expect(stateChanges.invokes).to.containSubset([ diff --git a/test/components/factory_v2/deletePoolByUser.spec.mjs b/test/components/factory_v2/deletePoolByUser.spec.mjs index effcc51df..c477aa072 100644 --- a/test/components/factory_v2/deletePoolByUser.spec.mjs +++ b/test/components/factory_v2/deletePoolByUser.spec.mjs @@ -253,6 +253,14 @@ describe('Factory V2 - deletePool by pool creator', /** @this {MochaSuiteModifie key: `%s%s__changeAmpTarget__${poolAddress}`, value: null, }, + { + key: `%s%s__amp__${poolAddress}`, + value: null, + }, + { + key: `%s%s__changeAmpLastCall__${poolAddress}`, + value: null, + }, ]); expect(stateChanges.invokes).to.containSubset([ diff --git a/test/components/lp_stable/_hooks.mjs b/test/components/lp_stable/_hooks.mjs index accc7bb84..f39ae692f 100644 --- a/test/components/lp_stable/_hooks.mjs +++ b/test/components/lp_stable/_hooks.mjs @@ -227,7 +227,7 @@ export const mochaHooks = { type: 'integer', value: '100000', }, { - key: '$s__outFeeDefault', + key: '%s__outFeeDefault', type: 'integer', value: '100000', }], @@ -299,12 +299,13 @@ export const mochaHooks = { const setAmpTx = data({ additionalFee: 4e5, data: [{ - key: '%s__amp', + key: `%s%s__amp__${address(this.accounts.lpStable, chainId)}`, type: 'string', value: '250', }], chainId, - }, this.accounts.lpStable); + senderPublicKey: publicKey(this.accounts.factoryV2), + }, this.accounts.manager); await api.transactions.broadcast(setAmpTx, {}); await waitForTx(setAmpTx.id, { apiBase });