Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement triggerCompliance, also implement compliance in V2 #333

Merged
merged 3 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ allprojects {
}

group = "exchange.dydx.abacus"
version = "1.6.54"
version = "1.6.55"

repositories {
google()
Expand Down
4 changes: 2 additions & 2 deletions integration/iOS/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ EXTERNAL SOURCES:
:path: "~/v4-abacus"

SPEC CHECKSUMS:
abacus: 46f62be6dc9b3f888093eb2c9952d0267ab40670
abacus: a57d55b0ca0d3514389573a87c47507f88eb6b0a
CryptoSwift: 562f8eceb40e80796fffc668b0cad9313284cfa6

PODFILE CHECKSUM: 37d72c15b180e62a4c42b8fb41b4836c89aa63c9

COCOAPODS: 1.15.2
COCOAPODS: 1.12.1
1 change: 0 additions & 1 deletion integration/iOS/Pods/Local Podspecs/abacus.podspec.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions integration/iOS/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

214 changes: 97 additions & 117 deletions integration/iOS/Pods/Pods.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package exchange.dydx.abacus.state.manager

import exchange.dydx.abacus.output.ComplianceAction
import exchange.dydx.abacus.output.Documentation
import exchange.dydx.abacus.output.Restriction
import exchange.dydx.abacus.output.input.SelectionOption
Expand Down Expand Up @@ -518,6 +519,15 @@ class AsyncAbacusStateManager(
}
}

override fun triggerCompliance(action: ComplianceAction, callback: TransactionCallback) {
try {
adaptor?.triggerCompliance(action, callback)
} catch (e: Exception) {
val error = V4TransactionErrors.error(null, e.toString())
callback(false, error, null)
}
}

internal fun parseTransactionResponse(response: String?): ParsingError? {
return adaptor?.parseTransactionResponse(response)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package exchange.dydx.abacus.state.manager

import exchange.dydx.abacus.output.ComplianceAction
import exchange.dydx.abacus.output.Documentation
import exchange.dydx.abacus.output.Restriction
import exchange.dydx.abacus.output.input.SelectionOption
Expand Down Expand Up @@ -80,6 +81,9 @@ interface AsyncAbacusStateManagerProtocol {

// Screen for restrictions
fun screen(address: String, callback: (restriction: Restriction) -> Unit)

// Trigger update for compliance
fun triggerCompliance(action: ComplianceAction, callback: TransactionCallback)
}

@JsExport
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ data class EnvironmentEndpoints(
val faucet: String?,
val squid: String?,
val nobleValidator: String?,
val geo: String?,
) {
companion object {
fun parse(
Expand All @@ -47,7 +48,8 @@ data class EnvironmentEndpoints(
val faucet = parser.asString(data["faucet"])
val squid = parser.asString(data["0xsquid"])
val nobleValidator = parser.asString(data["nobleValidator"])
return EnvironmentEndpoints(indexers, validators, faucet, squid, nobleValidator)
val geo = parser.asString(data["geo"])
return EnvironmentEndpoints(indexers, validators, faucet, squid, nobleValidator, geo)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1802,6 +1802,16 @@ open class StateManagerAdaptor(
callback(false, V4TransactionErrors.error(null, "Not implemented"), null)
}

internal open fun triggerCompliance(action: ComplianceAction, callback: TransactionCallback) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to your other PR, what is the purpose of the callback here? We're not doing anything asynchronous here.

accountAddress?.let {
if (compliance.status != ComplianceStatus.UNKNOWN) {
updateCompliance(DydxAddress(it), compliance.status, action)
callback(true, null, null)
}
}
callback(false, V4TransactionErrors.error(null, "No account address"), null)
}

internal open fun parseTransactionResponse(response: String?): ParsingError? {
return null
}
Expand Down Expand Up @@ -2454,13 +2464,14 @@ open class StateManagerAdaptor(
return compliance.status
}

private fun updateCompliance(address: DydxAddress, status: ComplianceStatus) {
private fun updateCompliance(address: DydxAddress, status: ComplianceStatus, complianceAction: ComplianceAction? = null) {
val message = "Compliance verification message"
val action = if ((stateMachine.state?.account?.subaccounts?.size ?: 0) > 0) {
ComplianceAction.CONNECT
} else {
ComplianceAction.ONBOARD
}
val action = complianceAction
?: if ((stateMachine.state?.account?.subaccounts?.size ?: 0) > 0) {
ComplianceAction.CONNECT
} else {
ComplianceAction.ONBOARD
}
val payload = jsonEncoder.encode(
mapOf(
"message" to message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ class V4StateManagerAdaptor(
return configs.publicApiUrl("screen")
}

override fun geoUrl(): String {
return "https://api.dydx.exchange/v4/geo"
override fun geoUrl(): String? {
return environment.endpoints.geo
}

override fun complianceScreenUrl(address: String): String? {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package exchange.dydx.abacus.state.v2.manager

import exchange.dydx.abacus.output.ComplianceAction
import exchange.dydx.abacus.output.Documentation
import exchange.dydx.abacus.output.Restriction
import exchange.dydx.abacus.output.input.SelectionOption
Expand Down Expand Up @@ -541,6 +542,15 @@ class AsyncAbacusStateManagerV2(
}
}

override fun triggerCompliance(action: ComplianceAction, callback: TransactionCallback) {
try {
adaptor?.triggerCompliance(action, callback)
} catch (e: Exception) {
val error = V4TransactionErrors.error(null, e.toString())
callback(false, error, null)
}
}

// Bridge functions.
// If client is not using cancelOrder function, it should call orderCanceled function with
// payload from v4-client to process state
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package exchange.dydx.abacus.state.v2.manager

import exchange.dydx.abacus.output.Compliance
import exchange.dydx.abacus.output.ComplianceAction
import exchange.dydx.abacus.output.ComplianceStatus
import exchange.dydx.abacus.output.Notification
import exchange.dydx.abacus.output.PerpetualState
import exchange.dydx.abacus.output.Restriction
Expand Down Expand Up @@ -70,6 +73,7 @@ import exchange.dydx.abacus.state.v2.supervisor.stopWatchingLastOrder
import exchange.dydx.abacus.state.v2.supervisor.subaccountNumber
import exchange.dydx.abacus.state.v2.supervisor.subaccountTransferPayload
import exchange.dydx.abacus.state.v2.supervisor.trade
import exchange.dydx.abacus.state.v2.supervisor.triggerCompliance
import exchange.dydx.abacus.state.v2.supervisor.triggerOrders
import exchange.dydx.abacus.state.v2.supervisor.triggerOrdersPayload
import exchange.dydx.abacus.state.v2.supervisor.withdrawPayload
Expand All @@ -81,6 +85,7 @@ import exchange.dydx.abacus.utils.Parser
import exchange.dydx.abacus.utils.UIImplementations
import kollections.JsExport
import kollections.iListOf
import kollections.toIMap

@JsExport
internal class StateManagerAdaptorV2(
Expand Down Expand Up @@ -170,6 +175,14 @@ internal class StateManagerAdaptorV2(
}
}

internal open var geo: String? = null
set(value) {
if (field != value) {
field = value
didSetGeo(value)
}
}

internal var readyToConnect: Boolean = false
internal set(value) {
if (field != value) {
Expand Down Expand Up @@ -298,6 +311,9 @@ internal class StateManagerAdaptorV2(
onboarding.readyToConnect = readyToConnect
markets.readyToConnect = readyToConnect
accounts.readyToConnect = readyToConnect
if (readyToConnect) {
fetchGeo()
}
}

private fun didSetIndexerConnected(indexerConnected: Boolean) {
Expand Down Expand Up @@ -429,6 +445,30 @@ internal class StateManagerAdaptorV2(
return null
}

private fun fetchGeo() {
val url = environment.endpoints.geo
if (url != null) {
networkHelper.get(
url,
null,
null,
callback = { _, response, httpCode, _ ->
geo = if (networkHelper.success(httpCode) && response != null) {
val payload = networkHelper.parser.decodeJsonObject(response)?.toIMap()
if (payload != null) {
val country = networkHelper.parser.asString(networkHelper.parser.value(payload, "geo.country"))
country
} else {
null
}
} else {
null
}
},
)
}
}

internal fun trade(data: String?, type: TradeInputField?) {
accounts.trade(data, type)
}
Expand Down Expand Up @@ -553,6 +593,10 @@ internal class StateManagerAdaptorV2(
accounts.screen(address, callback)
}

internal fun triggerCompliance(address: ComplianceAction, callback: TransactionCallback) {
accounts.triggerCompliance(address, callback)
}

private fun updateRestriction(indexerRestriction: UsageRestriction?) {
restriction = indexerRestriction ?: accounts.addressRestriction ?: UsageRestriction.noRestriction
}
Expand Down Expand Up @@ -589,4 +633,37 @@ internal class StateManagerAdaptorV2(
)
}
}

private fun didSetGeo(geo: String?) {
val state = stateMachine.state
stateMachine.state = PerpetualState(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kotlin tip: data class has a built-in copy() method:
stateMachine.state = stateMachine.state.copy(compliance = ...)

state?.assets,
state?.marketsSummary,
state?.orderbooks,
state?.candles,
state?.trades,
state?.historicalFundings,
state?.wallet,
state?.account,
state?.historicalPnl,
state?.fills,
state?.transfers,
state?.fundingPayments,
state?.configs,
state?.input,
state?.availableSubaccountNumbers ?: iListOf(),
state?.transferStatuses,
state?.restriction,
state?.launchIncentive,
Compliance(geo, state?.compliance?.status ?: ComplianceStatus.COMPLIANT),
)
ioImplementations.threading?.async(ThreadingType.main) {
stateNotification?.stateChanged(
stateMachine.state,
StateChanges(
iListOf(Changes.restriction),
),
)
}
}
}
Loading
Loading