iOS OS λ²μ μ΅μ μꡬμ¬ν
LunieWallet SDK λ iOS 15.0 μ΄μμ OS λ²μ μ μ§μν©λλ€. 15.0 λ―Έλ§μ OS λ²μ μμλ SDKλ₯Ό ν¬ν¨ν μ΄ν리μΌμ΄μ μ΄ λ°νμμ μ μμ μΌλ‘ ꡬλλμ§ μμ μ μμ΅λλ€. OS λ²μ μ κ΄λ ¨ν μμΈν μ 보λ iOS & IPad OS Release Note νμ΄μ§λ₯Ό μ°Έκ³ νμΈμ.
iOS νλ‘μ νΈμ Wallet SDK μ°λνκΈ°
- **
Project Target > Package Dependencies
λ©λ΄λ‘ μ΄λν λ€ [+] λ²νΌμ ν΄λ¦νμ¬ λ£¨λ μ§κ° SDK μμ‘΄μ±μ μ κ·λ‘ μΆκ°ν©λλ€.
- Repository:
Free to Download Wallet SDK
- Version: 1.0.0
- Nodit Console μ μ μνμ¬ κ°μ ν λ€, Wallet SDK Guide νμ΄μ§λ₯Ό μ°Έκ³ νμ¬ API Keyλ₯Ό λ°κΈ λ°μ΅λλ€.
- 2μμ λ°κΈλ°μ API Key μ¬μ©μ μν΄
config
νμΌμ μ κ· μμ±ν λ€ νμΌμ λ΄μ©μ μλμ κ°μ΄ μ€μ ν©λλ€. λΆν ν Key Sharesλ₯Ό μ μ₯ν μλ²μ Wallet API Keyμ νμν κ°μ μ λ ₯ν©λλ€.
projectFilePath/lunie_wallet_configuration.json
{
"webview_server_url": "${WALLET_WEBVIEW_URL}", // If not entered this field, the Nodit server will be used as the default.
"api_server_url": "${WALLET_API_URL}", // If not entered this field, the Nodit server will be used as the default.
"wallet_api_key":"${WALLET_API_KEY}" // required field
}
- WebView ν΅μ μ€μ μ μΆκ°ν©λλ€.
Project Target > Info
λ©λ΄λ‘ μ΄λν λ€, App Transport Security Settings νλͺ©κ³Ό Allow Arbitrary Loadsλ₯Ό Yesλ‘ μ€μ ν©λλ€.
<key>App Transport Security Settings </key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
- μΉ΄λ©λΌ μ€μ μ μΆκ°ν©λλ€.
//μΉ΄λ©λΌμ€μ μΆκ°
<key>NSCameraUsageDescription</key>
<string>Access camera</string>
//Face ID μ€μ μΆκ°
<key>Privacy - Face ID Usage Description</key>
<string>Please proceed with the authentication.</string>
SDK μ΄κΈ°ν λ° μ§κ° μμ±/λ‘λνκΈ°
- LunieWallet SDKλ₯Ό importν ν μλμ κ°μ΄ μ μΈνμ¬ SDKλ₯Ό μ΄κΈ°νν μ μμ΅λλ€.
import LunieWallet
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//initialize
Lunie.initialize()
GlobalManager.shared.lunieNetwork = NETWORK_ETHEREUM_GOERLI
return true
}
//...
}
- iOS Keychainμ μ μ₯λ μ§κ° μμ± μ΄λ ₯μ μ‘°νν ν, μ΄λ ₯μ΄ μμ κ²½μ° μ μ₯λ λλͺ¨λμ ν΅ν΄ μ§κ°μ λ‘λνκ³ μ΄λ ₯μ΄ μλ κ²½μ° μ κ· μ§κ° Instanceλ₯Ό μμ±ν μ μμ΅λλ€.
guard GlobalManager.shared.lunieWallet != nil else {
return
}
//1. Check Wallet existence
let isAlreadySet = LunieWallet.isAlreadySetWallet()
switch isAlreadySet {
case .Success(let isAlready):
if (isAlready) {
// 2. Load saved wallet from SecureLocalStorage
let lunieInstance = LunieWallet.getInstanceSavedWallet()
switch lunieInstance {
case .Success(let data):
GlobalManager.shared.lunieWallet = data
case .Fail(_):
GlobalManager.shared.lunieWallet = nil
Logger.debug("Fail Load Wallet")
}
}
case .Fail(_):
GlobalManager.shared.lunieWallet = nil
Logger.debug("Fail Load Wallet")
}
// Option 2-1. Create New Wallet
var network: LunieNetwork = .init(THE_BALANCE)
let wallet = LunieWallet.getInstanceNewWallet()
switch wallet {
case .Success(let data):
GlobalManager.shared.lunieWallet = data
showAlert("Success Create Wallet")
case .Fail(_):
showAlert("WALLET_ALREADY_INITIALIZED")
}
Wallet SDK API
iOS νκ²½μμ μ΄μ© κ°λ₯ν Wallet APIλ λ€μκ³Ό κ°μ΅λλ€.
Init For Use
λΌμ΄λΈλ¬λ¦¬ μ΄κΈ°ν ν¨μλ‘ Wallet SDK μ¬μ© μ νμλ‘ κ°μ₯ λ¨Όμ νΈμΆλμ΄μΌ ν©λλ€.
import LunieWallet
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//initialize Lunie
Lunie.initialize()
//initialize Network
GlobalManager.shared.lunieNetwork = .init(THE_BALANCE)
return true
}
//...
}
//GlobalManager.shared.lunieNetwork is initialized as a singleton LunieNetwork? object for use throughout the entire project.
import LunieWallet
class GlobalManager {
static let shared = GlobalManager()
var lunieWallet: LunieWallet?
var lunieNetwork: LunieNetwork?
var mpcData: SecretSharesOauth?
var shardKeys: [String] = []
}
Create New Wallet
μλ‘μ΄ mnemonic keyλ₯Ό μμ±ν ν μ΄λ₯Ό μ΄μ©νμ¬ Wallet Instanceλ₯Ό μμ±ν©λλ€.
import LunieWallet
let wallet = LunieWallet.getInstanceNewWallet()
switch wallet {
case .Success(let data):
GlobalManager.shared.lunieWallet = data
print("Success Create Wallet")
case .Fail(_):
print("WALLET_ALREADY_INITIALIZED")
}
Clear Wallet
νμ¬ λλ°μ΄μ€μ μ μ₯λ Walletμ Keyλ₯Ό μμ ν©λλ€. μ΄λ₯Ό μ΄μ©νμ¬ μλ‘μ΄ Keyλ₯Ό μμ±ν΄ μλ‘μ΄ μ£Όμμ μ§κ°μ μμ±ν μ μμ΅λλ€.
let result = LunieWallet.clearWallet()
switch result {
case .Success(let isclear):
if (isclear) {
print("Clear Wallet")
} else {
print("Clear Wallet Wrong")
}
case .Fail(_):
print("Clear Wallet Fail")
}
Check Wallet Existence
λλ°μ΄μ€μ μ μ₯λ μ§κ°μ΄ μ‘΄μ¬νλμ§ μ²΄ν¬ν ν κΈ°κΈ°μ μ μ₯λ mnemonic keyλ₯Ό λΆλ¬μ Wallet Instanceλ₯Ό μμ±ν©λλ€.
//1. Check Wallet existence
let isAlreadySet = LunieWallet.isAlreadySetWallet()
switch isAlreadySet {
case .Success(let isAlready):
if (isAlready) {
// 2. Load saved wallet from SecureLocalStorage
let lunieInstance = LunieWallet.getInstanceSavedWallet()
switch lunieInstance {
case .Success(let data):
GlobalManager.shared.lunieWallet = data
case .Fail(_):
GlobalManager.shared.lunieWallet = nil
print("Fail Load Wallet")
}
}
case .Fail(_):
GlobalManager.shared.lunieWallet = nil
print("There are no wallets to read from the device")
}
Load Wallet
νμ¬ λλ°μ΄μ€μ μ μ₯λ Wallet Instanceλ₯Ό νμΈν ν, Instanceκ° μ‘΄μ¬ν κ²½μ°, μ΄λ₯Ό λΆλ¬μ΅λλ€.
let lunieInstance = LunieWallet.getInstanceSavedWallet()
switch lunieInstance {
case .Success(let data):
GlobalManager.shared.lunieWallet = data
case .Fail(_):
GlobalManager.shared.lunieWallet = nil
print("Fail Load Wallet")
}
Recovery Wallet(MPC)
μ§κ°μ 볡ꡬνλ λ°©λ²μΌλ‘ λ°±μ ν΄ λ SecretSharesλ₯Ό μ΄μ©νμ¬ mnemonicμ 볡ꡬν©λλ€. κ·Έλ¦¬κ³ λ³΅κ΅¬ν mnemonicμ μ΄μ©νμ¬ Walletμ 볡ꡬν©λλ€.
// 1. Get secretShares for backup
var secretKeys : [String] = []
let wallet = LunieWallet.getSecretShares()
switch wallet {
case .Success(let keys):
secretKeys = keys
case .Fail(_):
print("Fail Load SecretKeys")
}
// 2. recovery wallet from secretShares
let lunieInstance = LunieWallet.recoveryWalletFromSecretKeys(secretKeys: secretKeys)
switch lunieInstance {
case .Success(let wallet):
GlobalManager.shared.lunieWallet = wallet
case .Fail(_):
GlobalManager.shared.lunieWallet = nil
print("Fail Load Wallet")
}
// 3. Recovery wallet from mnemonic
let mnemonic = ""
let recoveryWallet = LunieWallet.recoveryWalletFromMnemonic(mnemonic: mnemonic)
switch recoveryWallet {
case .Success(let wallet):
GlobalManager.shared.lunieWallet = wallet
case .Fail(_):
GlobalManager.shared.lunieWallet = nil
print("Fail Recovery Wallet")
}
Get Address
ν΄λΉ λ€νΈμν¬μ HD μ§κ° μ£Όμλ₯Ό μ‘°νν©λλ€.
let result = GlobalManager.shared.lunieNetwork?.getAddress()
switch result {
case .Success(let address):
print(address)
case .Fail(_):
print("getAddress Fail")
case .none:
print("getAddress none")
}
Get NFTs
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ ν΄λΉ μ§κ°μ΄ ν΄λΉ λ€νΈμν¬μ 보μ ν NFTλ₯Ό μ‘°νν©λλ€.
let page = 1 // page >= 1
let itemCount = 10 // 1 <= itemCount <= 100, Default value is 20
let address = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
GlobalManager.shared.lunieNetwork?.getNFTs(address: address, page: page, rpp: 10) { result in
switch result {
case .Success(let nftList):
print(nftList)
case .Fail(_):
print("Fail")
}
}
Get Native Token
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ ν΄λΉ μ§κ°μ΄ ν΄λΉ λ€νΈμν¬μ 보μ ν Native Tokenμ μ‘°νν©λλ€.
let address = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
GlobalManager.shared.lunieNetwork?.getNativeToken(address:address) { result in
switch result {
case .Success(let token):
print(token)
case .Fail(_):
print("Fail")
}
}
Get Tokens
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ ν΄λΉ μ§κ°μ΄ ν΄λΉ λ€νΈμν¬μ 보μ ν ERC20μ μ‘°νν©λλ€.
let address = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
GlobalManager.shared.lunieNetwork?.getTokens(address:address, page: 1, rpp: 10) { result in
switch result {
case .Success(let token):
print(token)
case .Fail(_):
print("Fail")
}
}
Get Gas Limit(NFT)
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ ν΄λΉ μ§κ°μ΄ ν΄λΉ λ€νΈμν¬μμ NFTλ₯Ό μ μ‘νκΈ° μν΄ νμν GasLimitμ μ‘°νν©λλ€.
let fromAddress = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
let toAddress = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
let nft = Nft(name: "", contractAddress: "", tokenId: 0, imageUri: "", mediaUri: "", description: "", properties: [], ownerAddress: fromAddress)
GlobalManager.shared.lunieNetwork?.getGasLimit(fromAddress: fromAddress, toAddress: toAddress, nft: nft) { result in
switch result {
case .Success(let gasLimit):
print(gasLimit)
case .Fail(_):
print("Fail")
}
}
Get Gas Limit(Token)
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ ν΄λΉ μ§κ°μ΄ ν΄λΉ λ€νΈμν¬μμ Tokenλ₯Ό μ μ‘νκΈ° μν΄ νμν GasLimitμ μ‘°νν©λλ€.
let fromAddress = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
let toAddress = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
let token = Token(name: "", contractAddress: "", symbol: "", decimal: 16, amount: BigInt(0))
GlobalManager.shared.lunieNetwork?.getGasLimit(fromAddress: fromAddress, toAddress: toAddress, token: token, amount: 0) { result in
switch result {
case .Success(let gasLimit):
print(gasLimit)
case .Fail(_):
print("Fail")
}
}
Get Gas Price
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ ν΄λΉ μ§κ°μ΄ ν΄λΉ λ€νΈμν¬μμ Transferλ₯Ό μ€ννκΈ° μν΄ νμν GasPriceλ₯Ό μ‘°νν©λλ€.
GlobalManager.shared.lunieNetwork?.getGasPrice() { result in
switch result {
case .Success(let gasprice):
print(gasprice)
case .Fail(_):
print("Fail")
}
}
Get Transaction Result By Hash
νΈλμμ μ Hashμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ ν΄λΉ νΈλμμ μ μμΈ λ΄μμ μ‘°νν©λλ€.
let hash = "<Transaction Hash>"
GlobalManager.shared.lunieNetwork?.getTransactionResultByHash(hash: hash) { result in
switch result {
case .Success(let transaction):
print(transaction)
case .Fail(_):
print("Fail")
}
}
Get Account Transaction Results
νΉμ μ£Όμλ₯Ό μ΄μ©νμ¬ νΈλμμ μ λ΄μμ μ‘°νν©λλ€.
let address = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
GlobalManager.shared.lunieNetwork?.getAccountTransactionResults(address: address, page: 1, rpp: 10){ result in
switch result {
case .Success(let transaction):
print(transaction)
case .Fail(_):
print("Fail")
}
}
Get Token Transaction From Address
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ ν΄λΉ μ£Όμμ ERC20 νΈλμμ μ μμΈ λ΄μμ μ‘°νν©λλ€.
let address = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
GlobalManager.shared.lunieNetwork?.getTokenTransactionFromAddress(address: address, page: 1, rpp: 10){ result in
switch result {
case .Success(let transaction):
print(transaction)
case .Fail(_):
print("Fail")
}
}
Transfer NFT
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ μ μ μ μ§κ°μ΄ 보μ ν NFTλ₯Ό νΉμ μ£Όμλ‘ μ μ‘νλ Transferλ₯Ό μ€νν©λλ€.
let toAddress = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
let nft = Nft(name: "", contractAddress: "", tokenId: 0, imageUri: "", mediaUri: "", description: "", properties: [])
GlobalManager.shared.lunieNetwork?.transferNFT(toAddress: toAddress, nft: nft, transferGasFee: nil) { result in
switch result {
case .Success(let transaction):
print(transaction)
case .Fail(_):
print("Fail")
}
}
Transfer Token
νΉμ μ£Όμμ λ€νΈμν¬λ₯Ό μ§μ νμ¬ μ μ μ μ§κ°μ΄ 보μ ν ERC20μ νΉμ μ£Όμλ‘ μ μ‘νλ Transferλ₯Ό μ€νν©λλ€.
let toAddress = "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
let token = Token(name: "", contractAddress: "", symbol: "", decimal: "", amount: BigInt(0))
GlobalManager.shared.lunieNetwork?.transferToken(toAddress: toAddress, token: token, amount: 0, transferGasFee:nil) { result in
switch result {
case .Success(let transaction):
print(transaction)
case .Fail(_):
print("Fail")
}
}
Wallet UI Component Setting
Wallet SDKλ νΈλ¦¬ν κ°λ°μ μ§μνκΈ° μν΄ κΈ°λ³Έμ μΈ WebViewλ₯Ό μ§μν©λλ€. μλ μ½λλ₯Ό μ΄μ©νμ¬ ν΄λΉ WebViewλ₯Ό νμΈν μ μμ΅λλ€.
DispatchQueue.main.async {
let lunieWebViewController = Lunie.getWebview()
self.present(lunieWebViewController, animated: true, completion: nil)
}
//OR
let lunieWebViewController = Lunie.getWebview()
let width = view.bounds.width
let height = view.bounds.height
lunieWebViewController.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
self.view.addSubview(lunieWebViewController.view)