
Kaptos SDK offers a unified API to interact with Aptos services, supporting customizable client settings and facilitating account management and transaction submission with domain-specific language features.
Kaptos is a Kotlin Multiplatform SDK for Aptos. It provides a common API for interacting with Aptos services across multiple platforms.
Add the following to your common source set:
commonMain.dependencies {
implementation("xyz.mcxross.kaptos:kaptos:<version>")
}Encrypted transaction construction is deliberately optional:
commonMain.dependencies {
implementation("xyz.mcxross.kaptos:kaptos-encrypted-transactions:<version>")
}Confidential balances, proofs, and asset operations are provided by a separate artifact:
commonMain.dependencies {
implementation("xyz.mcxross.kaptos:kaptos-confidential-assets:<version>")
}To add Kaptos to a platform-specific project, you can add the following to your platform-specific source set:
Kaptos provides two flavors for Android: kaptos-android and kaptos-android-debug. The kaptos-android flavor is
optimized for release builds, while the kaptos-android-debug flavor is optimized for debug builds.
dependencies {
implementation("xyz.mcxross.kaptos:kaptos-android:<version>")
}Kaptos provides artifacts for both iOS arm64 and x64 architectures. You can add the following to your iOS project:
dependencies {
implementation("xyz.mcxross.kaptos:kaptos-iosArm64:<version>")
}dependencies {
implementation("xyz.mcxross.kaptos:kaptos-iosX64:<version>")
}dependencies {
implementation("xyz.mcxross.kaptos:kaptos-macos:<version>")
}dependencies {
implementation("xyz.mcxross.kaptos:kaptos-jvm:<version>")
}[!NOTE] Snapshots are available via Sonatype Central's snapshots repository. To use snapshots, add the following to your project:
repositories {
maven("https://central.sonatype.com/repository/maven-snapshots/")
}Use the scoped aptos entry point for one workflow. It closes the shared transport and clears
accounts created through the client, whether the workflow succeeds or fails.
suspend fun main() = aptos(AptosConfig(network = Network.TESTNET)) {
val ledger = ledger.info()
println("Chain ${ledger.getOrNull()?.chainId}")
}Services are grouped by domain and share one configured transport. Construct Aptos
directly only when its lifetime is managed by a long-lived application scope.
aptos {
val framework = AccountAddress.fromString("0x1")
val account = accounts.get(framework)
val ledger = ledger.info()
val names = names.getAccountNames(framework)
}aptos {
accounts.getBalance(
address = framework,
asset = AccountAsset.coin("0x1::aptos_coin::AptosCoin"),
).fold(
onSuccess = { println("Balance: $it octas") },
onFailure = { println("Balance lookup failed: ${it.message}") },
)
}aptos {
val generated = account()
val imported = ed25519Account("ed25519-priv-0x...")
val message = "hello, Aptos"
val signature = imported.signText(message)
.getOrElse { failure -> error(failure.message) }
check(imported.verifySignature(message.encodeToByteArray(), signature))
}generated and imported are SDK-owned and cleared at the end of the block. An account supplied
by an external wallet remains caller-owned; Kaptos does not unexpectedly invalidate it.
The same service composes building, signing, submission, and confirmation. Amounts remain unsigned throughout the call.
aptos(AptosConfig(network = Network.TESTNET)) {
val alice = ed25519Account("ed25519-priv-0x...")
val payload = TransactionPayload.entryFunction(
function = "0x1::aptos_account::transfer",
arguments = listOf(
MoveArgument.Address(recipient),
MoveArgument.U64(1_000_000u),
),
)
val committed = transactions.submitAndWait(alice, payload)
.getOrElse { failure -> error(failure.message) }
println("Committed ${committed.hash}")
}Add kaptos-encrypted-transactions alongside the core SDK, using the same version. Import
encryptedTransactions to create a service on an existing Aptos instance. The service encrypts
the executable payload, signs the encrypted transaction, and submits it through the shared transport.
The configured fullnode must advertise an encryption key in its ledger response. Otherwise the
service returns AptosError.UnsupportedFeature. Use a funded standard signer; the encrypted
submission helpers reject Keyless signers, and encrypted transactions cannot be simulated.
import xyz.mcxross.kaptos.encrypted.encryptedTransactions
import xyz.mcxross.kaptos.model.TransactionPayload
import xyz.mcxross.kaptos.move.MoveArgument
// config selects a network with encrypted-transaction support; recipient is an AccountAddress.
aptos(config) {
val sender = ed25519Account("ed25519-priv-0x...")
val encrypted = encryptedTransactions()
val committed = encrypted.submitAndWait(
sender = sender,
payload = TransactionPayload.entryFunction(
function = "0x1::aptos_account::transfer",
arguments = listOf(
MoveArgument.Address(recipient),
MoveArgument.U64(1_000_000uL),
),
),
).getOrElse { failure -> error(failure.message) }
println("Committed ${committed.hash}")
}For multi-agent, fee-payer, or orderless flows, build an UnsignedTransaction through
transactions, then pass it to encrypted.signAndSubmit(transaction, sender, ...) with the
matching signers. Use encrypt(transaction) when signing and submission happen separately;
sign the returned encrypted transaction. EncryptedTransactionOptions accepts explicit signer
authentication keys and a claimed entry function. Reuse the service within a workflow and call
encrypted.clearCache() after a committed authentication-key rotation.
The encrypted transaction sample
runs with --args=encrypted and requires APTOS_PRIVATE_KEY, APTOS_RECIPIENT, and an
APTOS_NETWORK that supports encrypted transactions.
Add kaptos-confidential-assets alongside the core SDK, using the same version. Its
confidentialAssets() extension provides encrypted balance reads, proof-backed transfers and
withdrawals, deposits, and encryption-key management. The default Move module is
0x1::confidential_asset; use ConfidentialAssetConfig(moduleAddress = ...) for another deployment.
The selected network and fungible asset must support these operations. token is the asset's
metadata address, and the transaction signer needs funds for fees.
Confidential decryption keys are separate from transaction-signing keys. The following example imports a canonical 32-byte key supplied by the application's key storage and registers a new confidential balance. For an existing balance, import its registered key and omit registration.
import xyz.mcxross.kaptos.confidential.ConfidentialDecryptionKey
import xyz.mcxross.kaptos.confidential.confidentialAssets
// config, token (AccountAddress), and storedDecryptionKeyBytes come from the application.
aptos(config) {
val signer = ed25519Account("ed25519-priv-0x...")
val key = own(ConfidentialDecryptionKey.fromBytes(storedDecryptionKeyBytes))
val assets = confidentialAssets()
assets.registerBalance(signer = signer, token = token, key = key)
.getOrElse { failure -> error(failure.message) }
val balance = assets.getBalance(signer.accountAddress, token, key)
.getOrElse { failure -> error(failure.message) }
// balance.availableAmount and balance.pendingAmount contain the decrypted amounts.
}own(...) clears the imported key when the aptos scope closes; the application remains
responsible for retaining its stored key and clearing the source byte array. For disposable
registration examples, confidentialDecryptionKey() generates a key with the same managed
lifecycle. Keep a recoverable key for any balance that will hold funds.
Use deposit(signer, token, amount) to move public funds into the confidential balance and
rolloverPendingBalance(signer, token) to move pending funds into the available balance.
transfer(signer, recipient, token, key, amount) generates the transfer proofs; the recipient
must have a registered encryption key. withdraw(signer, token, key, amount) moves funds back
to a public balance. Amount arguments use ULong in the asset's smallest units.
Mutation methods wait for commitment and invalidate affected caches. Their build... counterparts
return unsigned transactions for separate signing or external fee-payer workflows.
ConfidentialTransactionOptions accepts gas settings and either a local fee-payer signer or an
external fee-payer address; submitting with an external payer requires separate signing.
The service also exposes normalization, incoming-transfer pause controls, key rotation, auditor
queries, and paginated activity. Balance reads are fresh by default; call assets.clearCache()
to discard cached balances and keys after changes made outside the service.
The confidential asset sample
runs with --args=confidential. It registers a generated key and requires APTOS_PRIVATE_KEY,
APTOS_CONFIDENTIAL_ASSET (the metadata address), and APTOS_NETWORK for the selected deployment.
Transactions and views share MoveArgument from xyz.mcxross.kaptos.move and TypeTag.
Typed views validate the function ABI and send BCS arguments; returned JSON values stay lossless.
import xyz.mcxross.kaptos.view.serialization.decodeValue
import kotlinx.serialization.builtins.serializer
import xyz.mcxross.kaptos.move.MoveArgument
import xyz.mcxross.kaptos.model.TypeTag
import xyz.mcxross.kaptos.model.flatMap
aptos {
val balance = views.call(
function = "0x1::coin::balance",
typeArguments = listOf(TypeTag.fromString("0x1::aptos_coin::AptosCoin")),
arguments = listOf(MoveArgument.Address(owner)),
).flatMap { it.decodeValue(0, ULong.serializer()) }
}Validation checks view status, argument and type-argument counts, concrete types, integer widths,
struct field names, and supported value shapes. Typed views reject opaque PreSerialized values,
including nested ones. Enum arguments use the ABI's explicit variants list and named fields;
missing layouts, unknown variants, and missing or extra fields are rejected. The codec never infers
variant layouts from struct fields. It does not infer JSON representations from BCS bytes. Move execution
and generic ability constraints are validated by the fullnode.
ledgerVersion applies to both ABI lookup and execution. Historical calls use an isolated codec;
current calls share the transaction codec and its preloaded module ABIs.
Use views.callRaw(function, typeArguments, arguments, ledgerVersion) for explicit JSON access.
Its type arguments are strings and arguments are JsonElement values; the fullnode validates
those raw values. decodeValue(index, deserializer) selects one return value using an explicit
serializer and reports invalid indexes or incompatible return types as typed errors.
Fetched ABIs expire after 60 seconds by default, with at most 128 fetched modules retained per
codec. Configure AptosConfig.abiCachePolicy to change those limits; a zero TTL disables fetched
caching. Failed refreshes return an error rather than using an expired ABI. Explicitly preloaded
ABIs stay pinned for offline builds. Call aptos.clearAbiCache() after a deployment to clear both
fetched and preloaded ABIs. Historical view calls keep their ABI lookup isolated at the requested
ledger version.
Ktor injection is available through an explicit adapter. The application retains ownership of an injected transport; the SDK manages its default transport.
import xyz.mcxross.kaptos.transport.ktor.asAptosTransport
val client = Aptos(AptosConfig(transport = httpClient.asAptosTransport()))Serializer-based view decoding is an extension in xyz.mcxross.kaptos.view.serialization.
The explicit raw JSON APIs continue to use kotlinx.serialization JSON values; these are intentional
integration boundaries, while transaction and typed-view arguments use SDK-owned types.
The framework-native helper derives the Aptos account address and constructs the exact SIWS
message from each entry-function transaction. A local Ed25519 account is convenient for tests;
production applications can provide a SolanaMessageSigner backed by their wallet UI.
aptos(AptosConfig(network = Network.TESTNET)) {
val fundingAccount = ed25519Account("ed25519-priv-0x...")
val abstracted = SolanaDerivableAccount.fromEd25519(
signer = fundingAccount,
domain = "wallet.example",
)
transactions.submitAndWait(
signer = abstracted,
payload = TransactionPayload.entryFunction(
function = "0x1::aptos_account::transfer",
arguments = listOf(
MoveArgument.Address(recipient),
MoveArgument.U64(1_000_000u),
),
),
)
}The derivable account must be funded before it can reserve transaction fees. Aptos removed
permissioned signers; do not use 0x1::permissioned_delegation::authenticate for new flows.
Runnable standard, sponsored, orderless, abstraction, encrypted-transaction, and
Confidential Asset examples are in sample/jvmApp.
Run a JVM example directly with Gradle. standard is the default when --args is omitted:
APTOS_PRIVATE_KEY='ed25519-priv-0x...' \
APTOS_RECIPIENT='0x...' \
APTOS_NETWORK='TESTNET' \
./gradlew :sample:jvmApp:run --args=standardOther accepted names are sponsored, orderless, abstraction, encrypted,
confidential, account, and multi-key. Each sample reports any additional environment values
it requires.
To run the SDK tests, simply run from the root of this repository:
[!NOTE] For a better experience, make sure there is an aptos local node process up and running (can check if there is a process running on port 8080).
./gradlew test Run ./scripts/install-git-hooks once per clone. Kotlin changes must pass ktfmt --google-style
before commits or stashes; use git stash-formatted for checked stashes. CI checks changed Kotlin
files as well. See the required formatting workflow.
All contributions to Kaptos are welcome. Before opening a PR, please submit an issue detailing the bug or feature. When opening a PR, please ensure that your contribution builds on the KMM toolchain, has been formatted with ktfmt --google-style, and contains tests when applicable. For more information, please see the contribution guidelines.
Copyright 2024 McXross
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Kaptos is a Kotlin Multiplatform SDK for Aptos. It provides a common API for interacting with Aptos services across multiple platforms.
Add the following to your common source set:
commonMain.dependencies {
implementation("xyz.mcxross.kaptos:kaptos:<version>")
}Encrypted transaction construction is deliberately optional:
commonMain.dependencies {
implementation("xyz.mcxross.kaptos:kaptos-encrypted-transactions:<version>")
}Confidential balances, proofs, and asset operations are provided by a separate artifact:
commonMain.dependencies {
implementation("xyz.mcxross.kaptos:kaptos-confidential-assets:<version>")
}To add Kaptos to a platform-specific project, you can add the following to your platform-specific source set:
Kaptos provides two flavors for Android: kaptos-android and kaptos-android-debug. The kaptos-android flavor is
optimized for release builds, while the kaptos-android-debug flavor is optimized for debug builds.
dependencies {
implementation("xyz.mcxross.kaptos:kaptos-android:<version>")
}Kaptos provides artifacts for both iOS arm64 and x64 architectures. You can add the following to your iOS project:
dependencies {
implementation("xyz.mcxross.kaptos:kaptos-iosArm64:<version>")
}dependencies {
implementation("xyz.mcxross.kaptos:kaptos-iosX64:<version>")
}dependencies {
implementation("xyz.mcxross.kaptos:kaptos-macos:<version>")
}dependencies {
implementation("xyz.mcxross.kaptos:kaptos-jvm:<version>")
}[!NOTE] Snapshots are available via Sonatype Central's snapshots repository. To use snapshots, add the following to your project:
repositories {
maven("https://central.sonatype.com/repository/maven-snapshots/")
}Use the scoped aptos entry point for one workflow. It closes the shared transport and clears
accounts created through the client, whether the workflow succeeds or fails.
suspend fun main() = aptos(AptosConfig(network = Network.TESTNET)) {
val ledger = ledger.info()
println("Chain ${ledger.getOrNull()?.chainId}")
}Services are grouped by domain and share one configured transport. Construct Aptos
directly only when its lifetime is managed by a long-lived application scope.
aptos {
val framework = AccountAddress.fromString("0x1")
val account = accounts.get(framework)
val ledger = ledger.info()
val names = names.getAccountNames(framework)
}aptos {
accounts.getBalance(
address = framework,
asset = AccountAsset.coin("0x1::aptos_coin::AptosCoin"),
).fold(
onSuccess = { println("Balance: $it octas") },
onFailure = { println("Balance lookup failed: ${it.message}") },
)
}aptos {
val generated = account()
val imported = ed25519Account("ed25519-priv-0x...")
val message = "hello, Aptos"
val signature = imported.signText(message)
.getOrElse { failure -> error(failure.message) }
check(imported.verifySignature(message.encodeToByteArray(), signature))
}generated and imported are SDK-owned and cleared at the end of the block. An account supplied
by an external wallet remains caller-owned; Kaptos does not unexpectedly invalidate it.
The same service composes building, signing, submission, and confirmation. Amounts remain unsigned throughout the call.
aptos(AptosConfig(network = Network.TESTNET)) {
val alice = ed25519Account("ed25519-priv-0x...")
val payload = TransactionPayload.entryFunction(
function = "0x1::aptos_account::transfer",
arguments = listOf(
MoveArgument.Address(recipient),
MoveArgument.U64(1_000_000u),
),
)
val committed = transactions.submitAndWait(alice, payload)
.getOrElse { failure -> error(failure.message) }
println("Committed ${committed.hash}")
}Add kaptos-encrypted-transactions alongside the core SDK, using the same version. Import
encryptedTransactions to create a service on an existing Aptos instance. The service encrypts
the executable payload, signs the encrypted transaction, and submits it through the shared transport.
The configured fullnode must advertise an encryption key in its ledger response. Otherwise the
service returns AptosError.UnsupportedFeature. Use a funded standard signer; the encrypted
submission helpers reject Keyless signers, and encrypted transactions cannot be simulated.
import xyz.mcxross.kaptos.encrypted.encryptedTransactions
import xyz.mcxross.kaptos.model.TransactionPayload
import xyz.mcxross.kaptos.move.MoveArgument
// config selects a network with encrypted-transaction support; recipient is an AccountAddress.
aptos(config) {
val sender = ed25519Account("ed25519-priv-0x...")
val encrypted = encryptedTransactions()
val committed = encrypted.submitAndWait(
sender = sender,
payload = TransactionPayload.entryFunction(
function = "0x1::aptos_account::transfer",
arguments = listOf(
MoveArgument.Address(recipient),
MoveArgument.U64(1_000_000uL),
),
),
).getOrElse { failure -> error(failure.message) }
println("Committed ${committed.hash}")
}For multi-agent, fee-payer, or orderless flows, build an UnsignedTransaction through
transactions, then pass it to encrypted.signAndSubmit(transaction, sender, ...) with the
matching signers. Use encrypt(transaction) when signing and submission happen separately;
sign the returned encrypted transaction. EncryptedTransactionOptions accepts explicit signer
authentication keys and a claimed entry function. Reuse the service within a workflow and call
encrypted.clearCache() after a committed authentication-key rotation.
The encrypted transaction sample
runs with --args=encrypted and requires APTOS_PRIVATE_KEY, APTOS_RECIPIENT, and an
APTOS_NETWORK that supports encrypted transactions.
Add kaptos-confidential-assets alongside the core SDK, using the same version. Its
confidentialAssets() extension provides encrypted balance reads, proof-backed transfers and
withdrawals, deposits, and encryption-key management. The default Move module is
0x1::confidential_asset; use ConfidentialAssetConfig(moduleAddress = ...) for another deployment.
The selected network and fungible asset must support these operations. token is the asset's
metadata address, and the transaction signer needs funds for fees.
Confidential decryption keys are separate from transaction-signing keys. The following example imports a canonical 32-byte key supplied by the application's key storage and registers a new confidential balance. For an existing balance, import its registered key and omit registration.
import xyz.mcxross.kaptos.confidential.ConfidentialDecryptionKey
import xyz.mcxross.kaptos.confidential.confidentialAssets
// config, token (AccountAddress), and storedDecryptionKeyBytes come from the application.
aptos(config) {
val signer = ed25519Account("ed25519-priv-0x...")
val key = own(ConfidentialDecryptionKey.fromBytes(storedDecryptionKeyBytes))
val assets = confidentialAssets()
assets.registerBalance(signer = signer, token = token, key = key)
.getOrElse { failure -> error(failure.message) }
val balance = assets.getBalance(signer.accountAddress, token, key)
.getOrElse { failure -> error(failure.message) }
// balance.availableAmount and balance.pendingAmount contain the decrypted amounts.
}own(...) clears the imported key when the aptos scope closes; the application remains
responsible for retaining its stored key and clearing the source byte array. For disposable
registration examples, confidentialDecryptionKey() generates a key with the same managed
lifecycle. Keep a recoverable key for any balance that will hold funds.
Use deposit(signer, token, amount) to move public funds into the confidential balance and
rolloverPendingBalance(signer, token) to move pending funds into the available balance.
transfer(signer, recipient, token, key, amount) generates the transfer proofs; the recipient
must have a registered encryption key. withdraw(signer, token, key, amount) moves funds back
to a public balance. Amount arguments use ULong in the asset's smallest units.
Mutation methods wait for commitment and invalidate affected caches. Their build... counterparts
return unsigned transactions for separate signing or external fee-payer workflows.
ConfidentialTransactionOptions accepts gas settings and either a local fee-payer signer or an
external fee-payer address; submitting with an external payer requires separate signing.
The service also exposes normalization, incoming-transfer pause controls, key rotation, auditor
queries, and paginated activity. Balance reads are fresh by default; call assets.clearCache()
to discard cached balances and keys after changes made outside the service.
The confidential asset sample
runs with --args=confidential. It registers a generated key and requires APTOS_PRIVATE_KEY,
APTOS_CONFIDENTIAL_ASSET (the metadata address), and APTOS_NETWORK for the selected deployment.
Transactions and views share MoveArgument from xyz.mcxross.kaptos.move and TypeTag.
Typed views validate the function ABI and send BCS arguments; returned JSON values stay lossless.
import xyz.mcxross.kaptos.view.serialization.decodeValue
import kotlinx.serialization.builtins.serializer
import xyz.mcxross.kaptos.move.MoveArgument
import xyz.mcxross.kaptos.model.TypeTag
import xyz.mcxross.kaptos.model.flatMap
aptos {
val balance = views.call(
function = "0x1::coin::balance",
typeArguments = listOf(TypeTag.fromString("0x1::aptos_coin::AptosCoin")),
arguments = listOf(MoveArgument.Address(owner)),
).flatMap { it.decodeValue(0, ULong.serializer()) }
}Validation checks view status, argument and type-argument counts, concrete types, integer widths,
struct field names, and supported value shapes. Typed views reject opaque PreSerialized values,
including nested ones. Enum arguments use the ABI's explicit variants list and named fields;
missing layouts, unknown variants, and missing or extra fields are rejected. The codec never infers
variant layouts from struct fields. It does not infer JSON representations from BCS bytes. Move execution
and generic ability constraints are validated by the fullnode.
ledgerVersion applies to both ABI lookup and execution. Historical calls use an isolated codec;
current calls share the transaction codec and its preloaded module ABIs.
Use views.callRaw(function, typeArguments, arguments, ledgerVersion) for explicit JSON access.
Its type arguments are strings and arguments are JsonElement values; the fullnode validates
those raw values. decodeValue(index, deserializer) selects one return value using an explicit
serializer and reports invalid indexes or incompatible return types as typed errors.
Fetched ABIs expire after 60 seconds by default, with at most 128 fetched modules retained per
codec. Configure AptosConfig.abiCachePolicy to change those limits; a zero TTL disables fetched
caching. Failed refreshes return an error rather than using an expired ABI. Explicitly preloaded
ABIs stay pinned for offline builds. Call aptos.clearAbiCache() after a deployment to clear both
fetched and preloaded ABIs. Historical view calls keep their ABI lookup isolated at the requested
ledger version.
Ktor injection is available through an explicit adapter. The application retains ownership of an injected transport; the SDK manages its default transport.
import xyz.mcxross.kaptos.transport.ktor.asAptosTransport
val client = Aptos(AptosConfig(transport = httpClient.asAptosTransport()))Serializer-based view decoding is an extension in xyz.mcxross.kaptos.view.serialization.
The explicit raw JSON APIs continue to use kotlinx.serialization JSON values; these are intentional
integration boundaries, while transaction and typed-view arguments use SDK-owned types.
The framework-native helper derives the Aptos account address and constructs the exact SIWS
message from each entry-function transaction. A local Ed25519 account is convenient for tests;
production applications can provide a SolanaMessageSigner backed by their wallet UI.
aptos(AptosConfig(network = Network.TESTNET)) {
val fundingAccount = ed25519Account("ed25519-priv-0x...")
val abstracted = SolanaDerivableAccount.fromEd25519(
signer = fundingAccount,
domain = "wallet.example",
)
transactions.submitAndWait(
signer = abstracted,
payload = TransactionPayload.entryFunction(
function = "0x1::aptos_account::transfer",
arguments = listOf(
MoveArgument.Address(recipient),
MoveArgument.U64(1_000_000u),
),
),
)
}The derivable account must be funded before it can reserve transaction fees. Aptos removed
permissioned signers; do not use 0x1::permissioned_delegation::authenticate for new flows.
Runnable standard, sponsored, orderless, abstraction, encrypted-transaction, and
Confidential Asset examples are in sample/jvmApp.
Run a JVM example directly with Gradle. standard is the default when --args is omitted:
APTOS_PRIVATE_KEY='ed25519-priv-0x...' \
APTOS_RECIPIENT='0x...' \
APTOS_NETWORK='TESTNET' \
./gradlew :sample:jvmApp:run --args=standardOther accepted names are sponsored, orderless, abstraction, encrypted,
confidential, account, and multi-key. Each sample reports any additional environment values
it requires.
To run the SDK tests, simply run from the root of this repository:
[!NOTE] For a better experience, make sure there is an aptos local node process up and running (can check if there is a process running on port 8080).
./gradlew test Run ./scripts/install-git-hooks once per clone. Kotlin changes must pass ktfmt --google-style
before commits or stashes; use git stash-formatted for checked stashes. CI checks changed Kotlin
files as well. See the required formatting workflow.
All contributions to Kaptos are welcome. Before opening a PR, please submit an issue detailing the bug or feature. When opening a PR, please ensure that your contribution builds on the KMM toolchain, has been formatted with ktfmt --google-style, and contains tests when applicable. For more information, please see the contribution guidelines.
Copyright 2024 McXross
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.