# Exchange Integration Guide(Java)
# Installation package
- Download Bytom Java SDK package. https://github.com/Bytom/bytom-java-sdk
- Open Bytom-sdk-java-{version No}.zip
- import Bytom-sdk-{version No}.jar and its related Package into Project
# Generate client
public static Client generateClient() throws BytomException {
String coreURL = Configuration.getValue("bytom.api.url");
String accessToken = Configuration.getValue("client.access.token");
if (coreURL == null || coreURL.isEmpty()) {
coreURL = "http://127.0.0.1:9888/";
}
return new Client(coreURL, accessToken);
}
Client client = Client.generateClient();
# Generate Address
Bytom blockchain use key - account - address model, it requires 3 steps to generate address
# Generate key
@Test
public void testClientKeyCreate() throws Exception {
String alias = "bob";
String password = "123456";
Key.Builder builder = new Key.Builder().setAlias(alias).setPassword(password);
Key key = Key.create(client, builder);
System.out.println(key.toJson());
}
Return
{
"alias":"bob",
"xpub":"10823b3b655d76c9122315bda4aded669b3087831c7e99379338d8d8d84296658cd866211a488dc234ec1ae6bbb11e6ad0e317311610e07cb2d0d098bd5f0c95",
"file":"/Users/doraemon/bytom/testnet/keystore/UTC--2021-07-21T06-58-38.437857000Z--18a0283e-9928-4492-9d65-0dc6ab72da70" //密钥文件地址
}
# Generate account
@Test
public void testAccountCreate() throws Exception {
String alias = "bob";
Integer quorum = 1;
List<String> root_xpubs = new ArrayList<>();
root_xpubs.add("10823b3b655d76c9122315bda4aded669b3087831c7e99379338d8d8d84296658cd866211a488dc234ec1ae6bbb11e6ad0e317311610e07cb2d0d098bd5f0c95");
Account.Builder builder = new Account.Builder().setAlias(alias).setQuorum(quorum).setRootXpub(root_xpubs);
account = Account.create(client, builder);
System.out.println(account.toJson());
}
Return:
{
"id":"9d26066f-e1ae-4e7a-88ce-2e871962db9c",
"alias":"bob",
"key_index":1,
"quorum":1,
"xpubs":[
"10823b3b655d76c9122315bda4aded669b3087831c7e99379338d8d8d84296658cd866211a488dc234ec1ae6bbb11e6ad0e317311610e07cb2d0d098bd5f0c95"
]
}
# Generate account address
@Test
public void testReceiverCreate1() throws Exception {
String alias = "bob";
String id = "9d26066f-e1ae-4e7a-88ce-2e871962db9c";
Account.ReceiverBuilder receiverBuilder = new Account.ReceiverBuilder().setAccountAlias(alias).setAccountId(id);
Receiver receiver = receiverBuilder.create(client);
System.out.println(receiver.toJson());
}
return:
{
"address":"bn1qu890dg0enz45mf7yrmmlmm70rzqzmcryuvu9p7",
"control_program":"0014e1caf6a1f998ab4da7c41ef7fdefcf18802de064"
}
# Verify the address
@Test
public void testAddressValidate() throws Exception {
String alias = "bob";
String id = "9d26066f-e1ae-4e7a-88ce-2e871962db9c";
Account.AddressBuilder addressBuilder = new Account.AddressBuilder().setAccountId(id).setAccountAlias(alias);
String address = "bn1qu890dg0enz45mf7yrmmlmm70rzqzmcryuvu9p7";
Account.Address accountAddress = addressBuilder.validate(client, address);
System.out.println(accountAddress.toJson());
}
Return "true" means it's a valid address
{
"valid":true,
"is_local":true
}
# Asset withdrawl (Transfer asset)
Transfer asset on Bytom blockchain needs Build - Sign - Submit three steps
# Build transaction
@Test
public void testSimplePayment() throws BytomException {
Transaction.Template payment = new Transaction.Builder()
.addAction(new Transaction.Action.SpendFromAccount()
.setAccountAlias("bob")
.setAssetAlias("btm")
.setAmount(220000000)
).addAction(new Transaction.Action.ControlWithAddress()
.setAddress("bn1qu890dg0enz45mf7yrmmlmm70rzqzmcryuvu9p7")
.setAssetAlias("btm")
.setAmount(100000000)
).addAction(new Transaction.Action.ControlWithAddress()
.setAddress("bn1qu890dg0enz45mf7yrmmlmm70rzqzmcryuvu9p7")
.setAssetAlias("btm")
.setAmount(100000000)
).build(client);
System.out.println(payment.toJson());
}
Return:
{
"raw_transaction":"070100010161015fcf9c0b3b1ccb8287fc89440a83f9bb2f965527f7e688e57589f0c23d30b8d9e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c8afa0250101160014ec4e90f8a63b2177b027250f0df76a85f70ffb5d0001000301003effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80eabbb72401160014ec4e90f8a63b2177b027250f0df76a85f70ffb5d000001003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c2d72f0116001407ddd06348cdd52c3f15f94a8a8be8c52eeebb8b000001003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c2d72f0116001496b42f069ed67d19663cc46c575f191ec022eee20000",
"signing_instructions":[
{
"position":0,
"witness_components":[
{
"type":"raw_tx_signature",
"quorum":1,
"keys":[
{
"xpub":"10823b3b655d76c9122315bda4aded669b3087831c7e99379338d8d8d84296658cd866211a488dc234ec1ae6bbb11e6ad0e317311610e07cb2d0d098bd5f0c95",
"derivation_path":[
"2c000000",
"99000000",
"01000000",
"00000000",
"01000000"
]
}
]
},
{
"type":"data",
"value":"0bca7cecfa25cfa751867083f9dcdbd32a7915018ec94675633d312c18f499a9",
"quorum":0
}
]
}
],
"local":false,
"allow_additional_actions":false
}
# Sign transaction
@Test
public void testSignPayment() throws BytomException {
Transaction.Template signedPayment = new Transaction.SignerBuilder().sign(client,payment, "123456");
System.out.println(signedPayment.toJson());
}
Return
{
"raw_transaction":"070100010161015fcf9c0b3b1ccb8287fc89440a83f9bb2f965527f7e688e57589f0c23d30b8d9e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c8afa0250101160014ec4e90f8a63b2177b027250f0df76a85f70ffb5d0063024071c211a8f9890e088169fd2b2b9a716df906d146d4aad03abb6b56e1fbbcc9342eb99632a5f576ee9985e0048cc358633e15cf85c21fe4a97254df4a9fc3b004200bca7cecfa25cfa751867083f9dcdbd32a7915018ec94675633d312c18f499a90301003effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80eabbb72401160014ec4e90f8a63b2177b027250f0df76a85f70ffb5d000001003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c2d72f0116001407ddd06348cdd52c3f15f94a8a8be8c52eeebb8b000001003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c2d72f0116001496b42f069ed67d19663cc46c575f191ec022eee20000",
"signing_instructions":[
{
"position":0,
"witness_components":[
{
"type":"raw_tx_signature",
"quorum":1,
"keys":[
{
"xpub":"10823b3b655d76c9122315bda4aded669b3087831c7e99379338d8d8d84296658cd866211a488dc234ec1ae6bbb11e6ad0e317311610e07cb2d0d098bd5f0c95",
"derivation_path":[
"2c000000",
"99000000",
"01000000",
"00000000",
"01000000"
]
}
],
"signatures":[
"71c211a8f9890e088169fd2b2b9a716df906d146d4aad03abb6b56e1fbbcc9342eb99632a5f576ee9985e0048cc358633e15cf85c21fe4a97254df4a9fc3b004"
]
},
{
"type":"data",
"value":"0bca7cecfa25cfa751867083f9dcdbd32a7915018ec94675633d312c18f499a9",
"quorum":0
}
]
}
],
"local":false,
"allow_additional_actions":false
}
# Submit transaction
@Test
public void testSubmitPayment() throws BytomException {
Transaction.SubmitResponse resp = Transaction.submit(client, signedPayment);
System.out.println(resp.toJson());
}
Return
{
"tx_id":"a9d6cfb172a186040579ffd9a16cd1092e57468579faa71225d0ac76098524d1"
}
# Transaction query
@Test
public void testGetTransaction() throws Exception {
String txID = "a9d6cfb172a186040579ffd9a16cd1092e57468579faa71225d0ac76098524d1";
Transaction.QueryBuilder query = new Transaction.QueryBuilder();
query.setTxId(txID);
Transaction transaction = query.get(client);
System.out.println(transaction.toJson());
}
Return
If there is "block_time" then it means the transaction has been put into a Block successfully.
{
"tx_id":"a9d6cfb172a186040579ffd9a16cd1092e57468579faa71225d0ac76098524d1",
"block_time":"1626852672000",
"block_hash":"16a8262434b956e3d60f48c67c11449e453cb48eb98892dbd44f84c46dca2dff",
"block_index":"1",
"block_transactions_count":"2",
"block_height":17209,
"inputs":[
{
"account_alias":"bob",
"account_id":"9d26066f-e1ae-4e7a-88ce-2e871962db9c",
"address":"bn1qu890dg0enz45mf7yrmmlmm70rzqzmcryuvu9p7",
"amount":10000000000,
"asset_alias":"BTM",
"asset_definition":{
"decimals":8,
"description":"Bytom Official Issue",
"name":"BTM",
"symbol":"BTM"
},
"asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"spent_output_id":"3d84ae5c0092a0188c4e4b573442d94abe5dab0a50291c8d13ad682ef1860832",
"type":"spend",
"control_program":"0014ec4e90f8a63b2177b027250f0df76a85f70ffb5d"
}
],
"outputs":[
{
"id":"eaa906f3cb88f1de0167b92f9bb8c6a00b54c3c016a4e90c9de71945e21e352f",
"type":"control",
"position":0,
"control_program":"0014ec4e90f8a63b2177b027250f0df76a85f70ffb5d",
"asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"asset_alias":"BTM",
"asset_definition":{
"decimals":8,
"description":"Bytom Official Issue",
"name":"BTM",
"symbol":"BTM"
},
"amount":9780000000,
"account_alias":"bob",
"account_id":"9d26066f-e1ae-4e7a-88ce-2e871962db9c",
"address":"bn1qu890dg0enz45mf7yrmmlmm70rzqzmcryuvu9p7"
},
{
"id":"3dc12eeca931d8507a0c8b7a0ab62f8711ee3277a98f4e71727df70cdb17d3a2",
"type":"control",
"position":1,
"control_program":"001407ddd06348cdd52c3f15f94a8a8be8c52eeebb8b",
"asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"asset_alias":"BTM",
"asset_definition":{
"decimals":8,
"description":"Bytom Official Issue",
"name":"BTM",
"symbol":"BTM"
},
"amount":100000000,
"account_alias":"bob",
"account_id":"9d26066f-e1ae-4e7a-88ce-2e871962db9c",
"address":"bn1qu890dg0enz45mf7yrmmlmm70rzqzmcryuvu9p7"
},
{
"id":"4078fe7930a696a1a2704969b33c6187f074c7307065bc1b7d102c1dc7db9f23",
"type":"control",
"position":2,
"control_program":"001496b42f069ed67d19663cc46c575f191ec022eee2",
"asset_id":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"asset_alias":"BTM",
"asset_definition":{
"decimals":8,
"description":"Bytom Official Issue",
"name":"BTM",
"symbol":"BTM"
},
"amount":100000000,
"address":"bn1qu890dg0enz45mf7yrmmlmm70rzqzmcryuvu9p7"
}
]
}
If we want make sure the Transaction cannot be reversed, we need to compare the block height info with the height in "chain-status" interface.
{
"status": "success",
"data": {
"current_height": 141421,
"current_hash": "5080d6d91e58b50e4f3542ae95983b849f4eb7cfaa1b196a1d8077217d47c9d5",
"finalized_height": 141300,
"finalized_hash": "0072b4497621fff3a9a1821a6365b6f65d2552c2f1749560a900746df37d7a1e",
"justified_height": 141400,
"justified_hash": "eb682b1ba23ad6db3b3206f87ab1b725b89951ee597695ed23cfd3a8c3a50ec1"
}
}
justified_height
Equal to 6 blocks of Bitcoin confirmation,finalized_height
unless more than 2 / 3 nodes commit evil, it is never possible to rollback