Skip to content

Commit

Permalink
WithdrawalGating
Browse files Browse the repository at this point in the history
  • Loading branch information
ruixhuang committed Aug 29, 2024
1 parent ef38a5a commit debcbd1
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ internal class TransferInputProcessor(
inputState.transfer.route = null

inputState.transfer.type = TransferType.deposit
val chainType = routerProcessor.defaultChainId()
if (chainType != null) {
updateTransferToChainType(inputState.transfer, chainType)
}
inputState.transfer.token = routerProcessor.defaultTokenAddress(chainType)

calculator.calculate(
transfer = inputState.transfer,
wallet = walletState,
Expand All @@ -75,20 +81,23 @@ internal class TransferInputProcessor(
when (inputField) {
TransferInputField.type -> {
val type = TransferType.invoke(data)
transfer.type = type
transfer.size =
TransferInputSize.safeCreate(transfer.size).copy(size = null, usdcSize = null)
transfer.route = null
transfer.memo = null
if (type == TransferType.transferOut) {
transfer.chain = "chain"
transfer.token = "usdc"
} else {
val chainType = routerProcessor.defaultChainId()
if (chainType != null) {
updateTransferToChainType(transfer, chainType)
if (transfer.type != type) {
transfer.type = type
transfer.size =
TransferInputSize.safeCreate(transfer.size)
.copy(size = null, usdcSize = null)
transfer.route = null
transfer.memo = null
if (type == TransferType.transferOut) {
transfer.chain = "chain"
transfer.token = "usdc"
} else {
val chainType = routerProcessor.defaultChainId()
if (chainType != null) {
updateTransferToChainType(transfer, chainType)
}
transfer.token = routerProcessor.defaultTokenAddress(chainType)
}
transfer.token = routerProcessor.defaultTokenAddress(chainType)
}
updated = true
}
Expand Down Expand Up @@ -188,6 +197,12 @@ internal class TransferInputProcessor(
updateTransferOutOptions(transfer)
}
}

transfer.resources = TransferInputResources.safeCreate(transfer.resources)
.copy(
chainResources = transfer.chainResources?.toIMap(),
tokenResources = transfer.tokenResources?.toIMap(),
)
}

return InputProcessorResult(
Expand Down Expand Up @@ -306,11 +321,6 @@ internal class TransferInputProcessor(
.copy(assets = tokenOptions.toIList())
transfer.withdrawalOptions = WithdrawalInputOptions.safeCreate(transfer.withdrawalOptions)
.copy(assets = tokenOptions.toIList())
transfer.resources = TransferInputResources.safeCreate(transfer.resources)
.copy(
chainResources = routerProcessor.chainResources(chainType)?.toIMap(),
tokenResources = routerProcessor.tokenResources(chainType)?.toIMap(),
)
}

private fun updateTransferToTokenType(
Expand Down Expand Up @@ -351,10 +361,6 @@ internal class TransferInputProcessor(
.copy(assets = tokenOptions.toIList())
transfer.withdrawalOptions = WithdrawalInputOptions.safeCreate(transfer.withdrawalOptions)
.copy(assets = tokenOptions.toIList())
transfer.resources = TransferInputResources.safeCreate(transfer.resources)
.copy(
tokenResources = routerProcessor.tokenResources(exchangeDestinationChainId)?.toIMap(),
)
}

transfer.exchange = exchange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,21 +637,28 @@ open class TradingStateMachine(
internal fun updateStateChanges(changes: StateChanges): StateChanges {
if (changes.changes.contains(Changes.input)) {
val subaccountNumber = changes.subaccountNumbers?.firstOrNull()

val subaccount = if (subaccountNumber != null) {
parser.asNativeMap(
parser.value(
this.account,
"subaccounts.$subaccountNumber",
),
)
if (staticTyping) {
val subaccount = internalState.wallet.account.subaccounts[subaccountNumber]
// Only run validation if the subaccount is null since updateState will run validation for each subaccount
if (subaccount == null) {
inputValidator.validate(
internalState = internalState,
subaccountNumber = subaccountNumber,
currentBlockAndHeight = currentBlockAndHeight,
environment = environment,
)
}
} else {
null
}

if (!staticTyping) {
// Skip this for static typing.. since the validator will be called in updateState().
// No need to call this twice.
val subaccount = if (subaccountNumber != null) {
parser.asNativeMap(
parser.value(
this.account,
"subaccounts.$subaccountNumber",
),
)
} else {
null
}
this.input = inputValidator.validateDeprecated(
subaccountNumber = subaccountNumber,
wallet = this.wallet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,34 @@ internal class WithdrawalCapacityValidator(
val configs = internalState.configs
val withdrawalCapacity = configs.withdrawalCapacity
val maxWithdrawalCapacity = withdrawalCapacity?.maxWithdrawalCapacity ?: BigDecimal.fromLong(Long.MAX_VALUE)
return null
val type = internalState.input.transfer.type ?: return null
val size = internalState.input.transfer.size
val usdcSize = parser.asDecimal(size?.usdcSize) ?: BigDecimal.ZERO
val usdcSizeInputIsGreaterThanCapacity = usdcSize > maxWithdrawalCapacity

if (type == TransferType.withdrawal && usdcSizeInputIsGreaterThanCapacity) {
return listOf(
error(
type = ErrorType.error,
errorCode = "",
fields = null,
actionStringKey = "WARNINGS.ACCOUNT_FUND_MANAGEMENT.WITHDRAWAL_LIMIT_OVER_ACTION",
titleStringKey = "WARNINGS.ACCOUNT_FUND_MANAGEMENT.WITHDRAWAL_LIMIT_OVER_TITLE",
textStringKey = "WARNINGS.ACCOUNT_FUND_MANAGEMENT.WITHDRAWAL_LIMIT_OVER_DESCRIPTION",
textParams = mapOf(
"USDC_LIMIT" to mapOf(
"value" to maxWithdrawalCapacity.doubleValue(false),
"format" to "price",
),
),
action = null,
link = environment?.links?.withdrawalGateLearnMore,
linkText = "APP.GENERAL.LEARN_MORE_ARROW",
),
)
} else {
return null
}
}

override fun validateTransferDeprecated(
Expand All @@ -40,11 +67,6 @@ internal class WithdrawalCapacityValidator(
environment: V4Environment?
): List<Any>? {
val withdrawalCapacity = parser.asMap(parser.value(configs, "withdrawalCapacity"))
// val maxWithdrawalCapacity = if (staticTyping) {
// internalState.configs.withdrawalCapacity?.maxWithdrawalCapacity ?: BigDecimal.fromLong(Long.MAX_VALUE)
// } else {
// parser.asDecimal(parser.value(withdrawalCapacity, "maxWithdrawalCapacity")) ?: BigDecimal.fromLong(Long.MAX_VALUE)
// }
val maxWithdrawalCapacity = parser.asDecimal(parser.value(withdrawalCapacity, "maxWithdrawalCapacity")) ?: BigDecimal.fromLong(Long.MAX_VALUE)
val type = parser.asString(parser.value(transfer, "type"))
val size = parser.asMap(parser.value(transfer, "size"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,44 @@ internal class WithdrawalGatingValidator(
restricted: Boolean,
environment: V4Environment?
): List<ValidationError>? {
return null
val currentBlock = currentBlockAndHeight?.block ?: Int.MAX_VALUE // parser.asInt(parser.value(environment, "currentBlock"))
val withdrawalGating = internalState.configs.withdrawalGating
val withdrawalsAndTransfersUnblockedAtBlock = withdrawalGating?.withdrawalsAndTransfersUnblockedAtBlock ?: 0
val blockDurationSeconds = if (environment?.isMainNet == true) 1.1 else 1.5
val secondsUntilUnblock = ((withdrawalsAndTransfersUnblockedAtBlock - currentBlock) * blockDurationSeconds).toInt()

val type = internalState.input.transfer.type ?: return null
when (type) {
TransferType.withdrawal, TransferType.transferOut -> {
if (secondsUntilUnblock > 0) {
return listOf(
error(
type = ErrorType.error,
errorCode = "",
fields = null,
actionStringKey = "WARNINGS.ACCOUNT_FUND_MANAGEMENT.${if (type == TransferType.withdrawal) "WITHDRAWAL_PAUSED_ACTION" else "TRANSFERS_PAUSED_ACTION"}",
titleStringKey = "WARNINGS.ACCOUNT_FUND_MANAGEMENT.${if (type == TransferType.withdrawal) "WITHDRAWAL_PAUSED_TITLE" else "TRANSFERS_PAUSED_TITLE"}",
textStringKey = "WARNINGS.ACCOUNT_FUND_MANAGEMENT.${if (type == TransferType.withdrawal) "WITHDRAWAL_PAUSED_DESCRIPTION" else "TRANSFERS_PAUSED_DESCRIPTION"}",
textParams = mapOf(
"SECONDS" to mapOf(
"value" to secondsUntilUnblock,
"format" to "string",
),
),
action = null,
link = environment?.links?.withdrawalGateLearnMore,
linkText = "APP.GENERAL.LEARN_MORE_ARROW",
),
)
} else {
return null
}
}

TransferType.deposit -> {
return null
}
}
}

override fun validateTransferDeprecated(
Expand All @@ -37,11 +74,6 @@ internal class WithdrawalGatingValidator(
): List<Any>? {
val currentBlock = currentBlockAndHeight?.block ?: Int.MAX_VALUE // parser.asInt(parser.value(environment, "currentBlock"))
val withdrawalGating = parser.asMap(parser.value(configs, "withdrawalGating"))
// val withdrawalsAndTransfersUnblockedAtBlock = if (staticTyping) {
// internalState.configs.withdrawalGating?.withdrawalsAndTransfersUnblockedAtBlock ?: 0
// } else {
// parser.asInt(withdrawalGating?.get("withdrawalsAndTransfersUnblockedAtBlock")) ?: 0
// }
val withdrawalsAndTransfersUnblockedAtBlock = parser.asInt(withdrawalGating?.get("withdrawalsAndTransfersUnblockedAtBlock")) ?: 0
val blockDurationSeconds = if (environment?.isMainNet == true) 1.1 else 1.5
val secondsUntilUnblock = ((withdrawalsAndTransfersUnblockedAtBlock - currentBlock) * blockDurationSeconds).toInt()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ internal typealias VerificationFunction = (response: StateResponse) -> Unit
open class BaseTests(
private val maxSubaccountNumber: Int,
private val useParentSubaccount: Boolean,
private val staticTyping: Boolean = true, // turn on static typing for testing
private val staticTyping: Boolean = false, // turn on static typing for testing
) {
open val doAsserts = true
internal val deploymentUri = "https://api.examples.com"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,39 @@ class V4SquidTests : V4BaseTests() {
test({
perp.transfer("DEPOSIT", TransferInputField.type, 0, environment = mock.v4Environment)
}, null, {
val summary = it.state?.input?.transfer?.summary!!
val summary =
if (perp.staticTyping) {
perp.internalState.input.transfer.summary
} else {
it.state?.input?.transfer?.summary!!
}
assertNotNull(summary)
assertTrue { summary.slippage!!.toInt() == 0 }
assertTrue { summary.exchangeRate!! > 0 }
assertTrue { summary.estimatedRouteDuration!! > 0 }
assertTrue { summary.gasFee!! > 0 }
// assertTrue { summary.bridgeFee!! > 0 }
assertNotNull(it.state?.input?.transfer?.requestPayload)
assertNotNull(it.state?.input?.transfer?.size?.usdcSize)
if (perp.staticTyping) {
val route = perp.internalState.input.transfer.route
val requestPayload = parser.asNativeMap(parser.value(route, "requestPayload"))
assertNotNull(requestPayload)
assertNotNull(perp.internalState.input.transfer.size?.usdcSize)
} else {
assertNotNull(it.state?.input?.transfer?.requestPayload)
assertNotNull(it.state?.input?.transfer?.size?.usdcSize)
}
})

test({
perp.transfer("0", TransferInputField.size, 0, environment = mock.v4Environment)
}, null, {
assertNull(it.state?.input?.transfer?.requestPayload)
if (perp.staticTyping) {
val route = perp.internalState.input.transfer.route
val requestPayload = parser.asNativeMap(parser.value(route, "requestPayload"))
assertNull(requestPayload)
} else {
assertNull(it.state?.input?.transfer?.requestPayload)
}
})
}

Expand Down
Loading

0 comments on commit debcbd1

Please sign in to comment.