The ecosystem "5 minute SDK" supports rich user experience and seamless blockchain integration.
Once the ecosystem SDK is integrated within a digital service, users will be be able to interact with rich earn and spend marketplace experiences, and view their account balance and order history.
A stellar wallet and account will be created behind the scenes for the user.
The SDK also support purchase API to allow users to create spend transaction within the app - see the following section: Using kin for native spend experience.
Next version of the SDK and API will also suport native earn and P2P transactions.
The fastest way to get started with the sdk is with cocoapods (>= 1.4.0).
pod 'KinEcosystem', '0.4.9'
Notice for apps using swift 3.2: the pod installation will change your project's swift version target to 4.0
This is because the sdk uses swift 4.0, and cocoapods force the pod's swift version on the project. For now, you can manually change your project's swift version in the build setting. A better solution will be available soon.
Digital service application needs to initiate the Ecosystem sdk, which interacts with the ecosystem backend service.
The Ecosystem backend is required for
- Creating users accounts on the Stellar blockchain
- Funds these account with initial XLM balance.
- Serving KIN earn and spend offers for the SDK marketplace.
- Mange and store user's earn and spend order history.
Therefore the ecosystem backend will block unauthorized requests. Digital services will have to authorised client request using one of the following methods:
- "whitelist" registration - used for quick first time integration or small internal testing.
- Whitelist registration requires a unique appID and apiKey.
- Please contact us to receive your unique appId and apiKey.
- "JWT" registration - A secure register method for production ready application,
- "JWT" registration" use a Server side signed JWT token to authenticated client request.
- You can learn more here
- Please contact us to receive your JWT issuer identifier (iss key) and provide us with your public signature key and its corresponding 'keyid'
Kin Ecosystem provides two working environments:
- PRODUCTION - Production ecosystem servers and the main private blockchain network.
- PLAYGROUND - A staging and testing environment running on test ecosystem servers and a private blockchain test network.
You must specify an Environment onKin.shared.start(...)
as you will see in the following section.
You should test the SDK with the PLAYGROUND enviorment using PLAYGROUND test credentials.
The PLAYGROUND enviorment SLA of is not guaranteed.
Playground transaction are running on Kin PLAYGROUND blockchain.
The PRODUCTION enviorment is runnig on main production blockchain and containing real earn/spend offers, therfore required specifc credtials per digital services, please contact us for more details.
-
Playground will support
ES256
andRS512
signature algorithm. -
PRODUCTION will only support
ES256
signature algorithm. -
The header will follow this template
{ "alg": "RS512", // We will support ES256 signature algorithem "typ": "JWT", "kid": string" // identifier of the keypair that was used to sign the JWT. identifiers and public keys will be provided by signer authority. This enables using multiple private/public key pairs (a list of public keys and their ids need to be provided by signer authority to verifier in advanced) }
-
Here is the registration payload template
{ // common/ standard fields iat: number; // issued at - seconds from epoc iss: string; // issuer - please contact us to recive your issuer exp: number; // expiration sub: "register" // application fields user_id: string; // id of the user - or a deterministic unique id for the user (hash) }
RS512_PRIVATE_KEY="MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQABAoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5CpuGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0KSu5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aPFaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw\=\="
APP_ID="test"
API_KEY="A2XEJTdN8hGiuUvg9VSHZ"
Once your app can provide a unique user id, call (depending on your onboarding method):
Kin.shared.start(userId: "myUserId", apiKey: "myAppKey", appId: "myAppId", environment: .playground)
Kin.shared.start(userId: "myUserId", jwt: encodedJWT, environment: .playground)
To view a full example of logging in with a JWT or an app key and id, check out the sample app
This will create the stack needed for running the ecosystem. All account creation and activation is handled for you by the sdk.
Because blockchain onboarding might take a few seconds, It is strongly recommended to call this function as soon as you can provide a user id.
To launch the marketplace experience, with earn and spend opportunities, from a viewController, simply call:
Kin.shared.launchMarketplace(from: self)
Once kin is onboarded, you can view the stellar wallet address using:
Kin.shared.publicAddress
note: this variable will return nil if called before kin is onboarded
Balance is represented by a Balance
struct:
public struct Balance: Codable, Equatable {
public var amount: Decimal
}
You can get your current balance using one of three ways:
if let amount = Kin.shared.lastKnownBalance?.amount {
print("your balance is \(amount) KIN")
} else {
// Kin is not started or an account wasn't created yet.
}
Kin.shared.balance { balance, error in
guard let amount = balance?.amount else {
if let error = error {
print("balance fetch error: \(error)")
}
return
}
print("your balance is \(amount) KIN")
}
var balanceObserverId: String? = nil
do {
balanceObserverId = try Kin.shared.addBalanceObserver { balance in
print("balance: \(balance.amount)")
}
} catch {
print("Error setting balance observer: \(error)")
}
// when you're done listening to balance changes, remove the observer:
if let observerId = balanceObserverId {
Kin.shared.removeBalanceObserver(observerId)
}
A native spend is a mechanism allowing your users to buy virtual goods you define, using Kin on Kin Ecosystem API’s.
A native spend offer requires you prepare an encoded jwt object, describing the offer:
- We will support
ES256
signature algorithm later on, right now you can useRS512
. - Header will follow this template
{
"alg": "RS512", // We will support ES256 signature algorithem
"typ": "JWT",
"kid": string" // identifier of the keypair that was used to sign the JWT. identifiers and public keys will be provided by signer authority. This enables using multiple private/public key pairs (a list of public keys and their ids need to be provided by signer authority to verifier in advanced)
}
- SpendOffer payload template
{
// common/ standard fields
iat: number; // issued at - seconds from epoc
iss: string; // issuer - please contact us to recive your issuer
exp: number; // expiration
sub: "spend"
// application fields
offer: {
id: string; // offer id is decided by you (internal)
amount: number; // amount of kin for this offer - price
}
sender: {
user_id: string; // optional: user_id who will perform the order
title: string; // order title - appears in order history
description: string; // order description - appears in order history
}
}
And to actually perform the purchase, call:
Kin.shared.purchase(offerJWT: encodedNativeOffer) { jwtConfirmation, error in
if let confirm = jwtConfirmation {
// success
} else if let e = error {
// error
}
}
A native spend example is also provided in the sample app
The Kin Marketplace offer wall displays built-in offers, which are served by the Kin Ecosystem Server. Their purpose is to provide users with opportunities to earn initial Kin funding, which they can later spend on spend offers provided by hosting apps.
You can also choose to display a banner for your custom offer in the Kin Marketplace offer wall. This serves as additional "real estate" in which to let the user know about custom offers within your app. When the user clicks on your custom Spend offer in the Kin Marketplace, your app is notified, and then it continues to manage the offer activity in its own UX flow.
NOTE: You will need to actively launch the Kin Marketplace offer wall so your user can see the offers you added to it.
To add a custom Spend offer to the Kin Marketplace:
- Create a
NativeSpendOffer
struct as in the example below.
let offer = NativeOffer(id: "offer id", // OfferId must be a UUID
title: "offer title",
description: "offer description",
amount: 1000,
image: "an image URL string",
isModal: true)
Note: setting a native offer's
isModal
property to true means that when a user taps on the native offer, the marketplace will first close (dismiss) before invoking the native offer's handler, if set. The default value is false.
- Set the
nativeOfferHandler
closure on Kin.shared to receive a callback when the native offer has been tapped.
The callback is of the formpublic var nativeOfferHandler: ((NativeOffer) -> ())?
// example from the sample app:
Kin.shared.nativeOfferHandler = { offer in
DispatchQueue.main.async {
let alert = UIAlertController(title: "Native Offer", message: "You tapped a native offer and the handler was invoked.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Close", style: .cancel, handler: { [weak alert] action in
alert?.dismiss(animated: true, completion: nil)
}))
let presentor = self.presentedViewController ?? self
presentor.present(alert, animated: true, completion: nil)
}
}
- Add the native offer you created in the following way:
Note: Each new offer is added as the first offer in Spend Offers list the Marketplace displays.
do {
try Kin.shared.add(nativeOffer: offer)
} catch {
print("failed to add native offer, error: \(error)")
}
To remove a custom Spend offer from the Kin Marketplace:
do {
try Kin.shared.remove(nativeOfferId: offer.id)
} catch {
print("Failed to remove offer, error: \(error)")
}
A custom Earn offer allows your users to earn Kin as a reward for performing tasks you want to incentivize, such as setting a profile picture or rating your app. (Custom offers are created by your app, as opposed to offers created by other platforms such as the Kin Ecosystem Server.)
NOTE: For now, custom Earn offers must be displayed and managed by your app, and cannot be added to the Kin Marketplace (unlike custom Spend offers).
Once the user has completed the task associated with the Earn offer, you request Kin payment for the user.
To request payment for a user who has completed an Earn offer:
-
Create a JWT that represents an Earn offer signed by you, using the header and payload templates below.
JWT header:
{ "alg": "ES256", // Hash function "typ": "JWT", "kid": string" // identifier of the keypair that was used to sign the JWT. identifiers and public keys will be provided by signer authority. This enables using multiple private/public key pairs (a list of public keys and their ids need to be provided by signer authority to verifier in advanced) }
JWT payload:
{ // common/ standard fields iat: number; // issued at - seconds from Epoch iss: string; // issuer exp: number; // expiration sub: "earn" // application fields offer: { id: string; // offer id is decided by you (internal) amount: number; // amount of kin for this offer - price } recipient: { user_id: string; // user_id who will perform the order title: string; // order title - appears in order history description: string; // order desc. (in order history) } }
-
Call
Kin.shared.requestPayment
(see code example below). The Ecosystem Server credits the user account (assuming the app’s account has sufficient funds).NOTES:
- The following snippet is taken from the SDK Sample App, in which the JWT is created and signed by the client side for presentation purposes only. Do not use this method in production! In production, the JWT must be signed by the server, with a secure private key.
let handler: ExternalOfferCallback = { jwtConfirmation, error in let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert) if let confirm = jwtConfirmation { alert.title = "Success" alert.message = "Earn complete. You can view the confirmation on jwt.io" alert.addAction(UIAlertAction(title: "View on jwt.io", style: .default, handler: { [weak alert] action in UIApplication.shared.openURL(URL(string:"https://jwt.io/#debugger-io?token=\(confirm)")!) alert?.dismiss(animated: true, completion: nil) })) } else if let e = error { alert.title = "Failure" alert.message = "Earn failed (\(e.localizedDescription))" } alert.addAction(UIAlertAction(title: "Close", style: .cancel, handler: { [weak alert] action in alert?.dismiss(animated: true, completion: nil) })) self?.present(alert, animated: true, completion: nil) } Kin.shared.requestPayment(offerJWT: encodedJWT, completion: handler)
The kin-ecosystem-ios-sdk library is licensed under MIT license.