Quickstart for Android

πŸ“˜

Android OS μ΅œμ†Œ μš”κ΅¬μ‚¬ν•­

LunieWallet SDKλŠ” μ•ˆλ“œλ‘œμ΄λ“œ API Level 23 이상을 μ§€μ›ν•˜λŠ” μ•ˆλ“œλ‘œμ΄λ“œ OS 버전을 μ§€μ›ν•©λ‹ˆλ‹€. 23 미만의 API Level을 μ‚¬μš©ν•˜λŠ” OS λ²„μ „μ—μ„œλŠ” SDKλ₯Ό ν¬ν•¨ν•œ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λŸ°νƒ€μž„μ— μ •μƒμ μœΌλ‘œ κ΅¬λ™λ˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. 각 OS 버전 별 지원 API Level을 ν™•μΈν•˜λ €λ©΄ μ•ˆλ“œλ‘œμ΄λ“œ Release Note νŽ˜μ΄μ§€λ₯Ό μ°Έκ³ ν•˜μ„Έμš”.

μ•ˆλ“œλ‘œμ΄λ“œ ν”„λ‘œμ νŠΈμ— Wallet SDK μ—°λ™ν•˜κΈ°

  1. Wallet SDKλ₯Ό λ‹€μš΄λ‘œλ“œ 받은 λ’€ lib 폴더 ν•˜μœ„μ— μ €μž₯ν•©λ‹ˆλ‹€.
  2. app/build.gradle νŒŒμΌμ— μ•„λž˜μ™€ 같이 μ˜μ‘΄μ„±μ„ μΆ”κ°€ν•©λ‹ˆλ‹€.
...
dependencies {
  	implementation files('../lib/LunieWalletSDK.aar')
  	implementation "org.web3j:core:4.8.8-android"
  	implementation "com.squareup.retrofit2:retrofit:2.9.0"
  	implementation "com.squareup.retrofit2:converter-gson:2.9.0"
  	implementation "androidx.security:security-crypto:1.0.0"
  	implementation 'com.google.zxing:core:3.2.1'
}
  1. Nodit μ½˜μ†” 에 μ ‘μ†ν•˜μ—¬ κ°€μž…ν•œ λ’€, Wallet SDK Guide νŽ˜μ΄μ§€λ₯Ό μ°Έκ³ ν•˜μ—¬ Environment API Keyλ₯Ό λ°œκΈ‰ν•©λ‹ˆλ‹€.
  2. 3μ—μ„œ λ°œκΈ‰λ°›μ€ API Key μ‚¬μš©μ„ μœ„ν•΄ configνŒŒμΌμ„ μƒμ„±ν•œ ν›„ Wallet API Keyλ₯Ό μž…λ ₯ν•©λ‹ˆλ‹€. config 파일의 κ²½λ‘œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. serverλ₯Ό μž…λ ₯ν•˜μ§€ μ•ŠλŠ” 경우, default둜 Nodit의 μ„œλ²„λ₯Ό μ΄μš©ν•˜κ²Œ λ©λ‹ˆλ‹€.
  • projectFilePath/app/src/assets/lunie_wallet_configuration.json
{ 
  "webview_server_url": "${WALLET_WEBVIEW_URL}", // If not entered, the Nodit server will be used as the default.
  "api_server_url": "${WALLET_API_URL}", // If not entered, the Nodit server will be used as the default.
  "wallet_api_key":"${WALLET_API_KEY}" // required field
}


SDK μ΄ˆκΈ°ν™” 및 지갑 생성/λ‘œλ“œν•˜κΈ°

  1. LunieWallet SDKλ₯Ό importν•œ ν›„ μ•„λž˜μ™€ 같이 μ„ μ–Έν•˜μ—¬ SDKλ₯Ό μ΄ˆκΈ°ν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
Lunie.init(applicationContext)
  1. μ•ˆλ“œλ‘œμ΄λ“œ Keystore에 μ €μž₯된 지갑 생성 이λ ₯을 μ‘°νšŒν•œ ν›„, 이λ ₯이 μžˆμ„ 경우 μ €μž₯된 mnemonic 톡해 지갑을 λ‘œλ“œν•˜κ³  이λ ₯이 μ—†λŠ” 경우 μ‹ κ·œ 지갑 Instanceλ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.
//1. Check Wallet exist
val isAlreadySet = when (val result = LunieWallet.isAlreadySetWallet()) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
       Log.e("LunieWallet", result.error.message ?: "Unknown Error")
       return
    }
}

// Option 2-1. Load wallet from stored mnemonic in SecureLocalStorage if isAlreadySet ==1
val wallet = when (val result = LunieWallet.getInstanceSavedWallet()) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

// Option 2-2. Create new wallet if isAlreadySet == 0
val wallet = when (val result = LunieWallet.getInstanceNewWallet()) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Wallet SDK API

Init For Use

라이브러리 μ΄ˆκΈ°ν™” ν•¨μˆ˜λ‘œ LunieWallet SDK μ‚¬μš© μ „ ν•„μˆ˜λ‘œ κ°€μž₯ λ¨Όμ € ν˜ΈμΆœλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

Lunie.init(applicationContext)

Create New Wallet

μƒˆλ‘œμš΄ mnemonic keyλ₯Ό μƒμ„±ν•œ ν›„ 이λ₯Ό μ΄μš©ν•˜μ—¬ Wallet Instanceλ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.

val wallet = when (val result = LunieWallet.getInstanceNewWallet()) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Check Wallet Existence

ν˜„μž¬ λ””λ°”μ΄μŠ€μ— μ €μž₯된 Wallet Instanceκ°€ μžˆλŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.

val isAlreadySet = when (val result = LunieWallet.isAlreadySetWallet()) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Load Wallet

ν˜„μž¬ λ””λ°”μ΄μŠ€μ— μ €μž₯된 Wallet Instanceλ₯Ό ν™•μΈν•œ ν›„, Instanceκ°€ μ‘΄μž¬ν•  경우, 이λ₯Ό Load ν•©λ‹ˆλ‹€.

//1. Check Wallet existence
val isAlreadySet = when (val result = LunieWallet.isAlreadySetWallet()) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

if(isAlreadySet) {
    // 2. Load saved wallet from SecureLocalStorage
    val wallet = when (val result = LunieWallet.getInstanceSavedWallet()) {
        is LunieWalletResult.Success -> result.data
        is LunieWalletResult.Fail -> {
            Log.e("LunieWallet", result.error.message ?: "Unknown Error")
            return
        }
    }
} else {
    // create new one
}

Recovery Wallet(MPC)

지갑을 λ³΅κ΅¬ν•˜λŠ” λ°©λ²•μœΌλ‘œ λ°±μ—…ν•΄ λ‘” SecretSharesλ₯Ό μ΄μš©ν•˜μ—¬ mnemonic을 λ³΅κ΅¬ν•©λ‹ˆλ‹€. 그리고 λ³΅κ΅¬ν•œ mnemonic을 μ΄μš©ν•˜μ—¬ Wallet을 λ³΅κ΅¬ν•©λ‹ˆλ‹€.

// 1. Get secretShares for backup
val secretShares = when (val result = wallet.getSecretShares()) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

// 2. Recovery wallet from secretShares
val wallet = when (val result = LunieWallet.recoveryWalletFromSecretKeys(secretShares)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

// 3. Recovery wallet from mnemonic
val wallet = when (val result = LunieWallet.recoveryWalletFromMnemonic(mnemonic)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get Address

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή 지갑이 ν•΄λ‹Ή λ„€νŠΈμ›Œν¬μ— λ³΄μœ ν•œ μžμ‚°μ„ μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val address = when (val result = network.getAddress(wallet)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get NFTs

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή 지갑이 ν•΄λ‹Ή λ„€νŠΈμ›Œν¬μ— λ³΄μœ ν•œ NFTλ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val address = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val (page, itemCount) = 1 to 10
val nftCollections = when (val result = network.getNFTs(address, page, itemCount)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get Native Token

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή 지갑이 ν•΄λ‹Ή λ„€νŠΈμ›Œν¬μ— λ³΄μœ ν•œ Native Token을 μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val address = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val nativeTokenBalance = when (val result = network.getNativeToken(address)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get Tokens

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή 지갑이 ν•΄λ‹Ή λ„€νŠΈμ›Œν¬μ— λ³΄μœ ν•œ ERC20을 μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val address = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val (page, itemCount) = 1 to 10
val tokenBalances = when (val result = network.getTokens(address, page, itemCount)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get Gas Limit(NFT)

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή 지갑이 ν•΄λ‹Ή λ„€νŠΈμ›Œν¬μ—μ„œ NFTλ₯Ό μ „μ†‘ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•œ GasLimit을 μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val toAddress = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val gaslimit = when (val result = network.getGasLimit(lunieWallet, toAddress, nft)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get Gas Limit(Token)

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή 지갑이 ν•΄λ‹Ή λ„€νŠΈμ›Œν¬μ—μ„œ Tokenλ₯Ό μ „μ†‘ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•œ GasLimit을 μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val toAddress = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val gaslimit = when (val result = network.getGasLimit(lunieWallet, toAddress, token, tokenAmount)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get Gas Price

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή 지갑이 ν•΄λ‹Ή λ„€νŠΈμ›Œν¬μ—μ„œ Transferλ₯Ό μ‹€ν–‰ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•œ GasPriceλ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val toAddress = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val gasPrice = when (val result = network.getGasPrice()) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get Transaction Result By Hash

νŠΈλžœμž­μ…˜μ˜ Hash와 λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή νŠΈλžœμž­μ…˜μ˜ 상세 내역을 μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val transactionHash = "0xf2edcf8f59cfce9350785f4d9cbdaa7ce76f6fabd4a3a96c3de82b91237973a1"
val transactionResult = when (val result = network.getTransactionResultByHash(transactionHash)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Get Account Transaction Results

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή μ£Όμ†Œκ°€ ν¬ν•¨λœ νŠΈλžœμž­μ…˜μ˜ 전체 내역을 μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val address = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val (page, itemCount) = 1 to 10
val transactionResults =
    when (val result = network.getAccountTransactionResults(address, page, itemCount)) {
        is LunieWalletResult.Success -> result.data
        is LunieWalletResult.Fail -> {
            Log.e("LunieWallet", result.error.message ?: "Unknown Error")
            return
        }
    }

Get Token transaction From Address

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ ν•΄λ‹Ή μ£Όμ†Œμ˜ ERC20 νŠΈλžœμž­μ…˜μ˜ 상세 내역을 μ‘°νšŒν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val address = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val (page, itemCount) = 1 to 10
val transactionResults =
    when (val result = network.getTokenTransactionFromAddress(address, page, itemCount)) {
        is LunieWalletResult.Success -> result.data
        is LunieWalletResult.Fail -> {
            Log.e("LunieWallet", result.error.message ?: "Unknown Error")
            return
        }
    }

Transfer NFT

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ μœ μ €μ˜ 지갑이 λ³΄μœ ν•œ NFTλ₯Ό νŠΉμ • μ£Όμ†Œλ‘œ μ „μ†‘ν•˜λŠ” Transferλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val tdAddress = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val transactionHash = when (val result = network.transferNFT(lunieWallet, tdAddress, nft)) {
    is LunieWalletResult.Success -> result.data
    is LunieWalletResult.Fail -> {
        Log.e("LunieWallet", result.error.message ?: "Unknown Error")
        return
    }
}

Transfer Token

νŠΉμ • μ£Όμ†Œμ™€ λ„€νŠΈμ›Œν¬λ₯Ό μ§€μ •ν•˜μ—¬ μœ μ €μ˜ 지갑이 λ³΄μœ ν•œ ERC20을 νŠΉμ • μ£Όμ†Œλ‘œ μ „μ†‘ν•˜λŠ” Transferλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

val network = NETWORK_THE_BALANCE
val tdAddress = "0x9baCE0756260de6d28A89AcfcBf37BC512ff2333"
val transactionHash =
    when (val result = network.transferToken(lunieWallet, tdAddress, token, amount)) {
        is LunieWalletResult.Success -> result.data
        is LunieWalletResult.Fail -> {
            Log.e("LunieWallet", result.error.message ?: "Unknown Error")
            return
        }
    }

Wallet UI Component Setting

Wallet SDKλŠ” νŽΈλ¦¬ν•œ κ°œλ°œμ„ μ§€μ›ν•˜κΈ° μœ„ν•΄ 기본적인 WebViewλ₯Ό μ§€μ›ν•©λ‹ˆλ‹€. μ•„λž˜ μ½”λ“œλ₯Ό μ΄μš©ν•˜μ—¬ ν•΄λ‹Ή WebViewλ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

// 1. WalletView Initial Setting
override fun onCreateView() {
    ...
    lunieWalletView.init(wallet)
}
<LinearLayout 
	android:layout_width="match_parent"
	android:layout_height="match_parent">
	<com.lambda256.walletsdk.LunieWalletView
		android:layout_width="match_parent"
		android:layout_height="match_parent"/>
</LinearLayout>