3 import com.google.gson.annotations.SerializedName;
4 import io.bytom.common.ParameterizedTypeImpl;
5 import io.bytom.common.Utils;
6 import io.bytom.exception.BytomException;
7 import io.bytom.http.Client;
8 import org.apache.log4j.Logger;
10 import java.lang.reflect.Type;
14 * <h1>Transaction Class</h1>
16 public class Transaction {
18 * Unique identifier, or transaction hash, of a transaction.
20 @SerializedName("tx_id")
24 * Time of transaction.
26 @SerializedName("block_time")
27 public String blockTime;
30 * Unique identifier, or block hash, of the block containing a transaction.
32 @SerializedName("block_hash")
33 public String blockHash;
36 * Index of a transaction within the block.
38 @SerializedName("block_index")
39 public String blockIndex;
41 @SerializedName("block_transactions_count")
42 public String blockTransactionsCount;
45 * Height of the block containing a transaction.
47 @SerializedName("block_height")
48 public int blockHeight;
51 * whether the state of the request has failed.
53 @SerializedName("status_fail")
54 public boolean statusFail;
57 * List of specified inputs for a transaction.
59 public List<Input> inputs;
62 * List of specified outputs for a transaction.
64 public List<Output> outputs;
66 private static Logger logger = Logger.getLogger(Transaction.class);
69 * Serializes the Address into a form that is safe to transfer over the wire.
71 * @return the JSON-serialized representation of the Receiver object
73 public String toJson() {
74 return Utils.serializer.toJson(this);
77 public static class Builder {
79 * Hex-encoded serialization of a transaction to add to the current template.
81 @SerializedName("base_transaction")
82 protected String baseTransaction;
85 * List of actions in a transaction.
87 protected List<Action> actions;
90 * A time duration in milliseconds. If the transaction is not fully signed and
91 * submitted within this time, it will be rejected by the blockchain.
92 * Additionally, any outputs reserved when building this transaction will remain
93 * reserved for this duration.
98 * Call build-transaction api.<br>
100 * Builds a single transaction template.
102 * @param client client object which makes requests to the server
103 * @return a transaction template
105 public Template build(Client client) throws BytomException {
106 return client.request("build-transaction", this, Template.class);
110 * Default constructor initializes actions list.
113 this.actions = new ArrayList<>();
117 * Sets the baseTransaction field and initializes the actions lists.<br>
118 * This constructor can be used when executing an atomic swap and the counter
119 * party has sent an initialized tx template.
121 public Builder(String baseTransaction) {
122 this.setBaseTransaction(baseTransaction);
123 this.actions = new ArrayList<>();
127 * Sets the base transaction that will be added to the current template.
129 public Builder setBaseTransaction(String baseTransaction) {
130 this.baseTransaction = baseTransaction;
135 * Adds an action to a transaction builder.
136 * @param action action to add
137 * @return updated builder object
139 public Builder addAction(Action action) {
140 this.actions.add(action);
145 * Sets a transaction's time-to-live, which indicates how long outputs will be
146 * reserved for, and how long the transaction will remain valid. Passing zero will
147 * use the default TTL, which is 300000ms (5 minutes).
148 * @param ms the duration of the TTL, in milliseconds.
149 * @return updated builder object
151 public Builder setTtl(long ms) {
157 public static class QueryBuilder {
161 public String accountId;
163 public QueryBuilder setTxId(String txId) {
168 public QueryBuilder setAccountId(String accountId) {
169 this.accountId = accountId;
175 * call list-transactions api
177 * @param client client object that makes requests to the core
178 * @return Transaction Info
179 * @throws BytomException BytomException
181 public List<Transaction> list(Client client) throws BytomException {
183 Type listType = new ParameterizedTypeImpl(List.class, new Class[]{Transaction.class});
184 List<Transaction> transactionList = client.request("list-transactions", null, listType);
186 logger.info("list-transactions:");
187 logger.info("size of transactionList:" + transactionList.size());
188 logger.info("all transactions:");
189 for (int i = 0; i < transactionList.size(); i++) {
190 logger.info(transactionList.get(i).toJson());
193 return transactionList;
196 public List<Transaction> listById(Client client) throws BytomException {
197 Map<String, Object> req = new HashMap<String, Object>();
198 req.put("tx_id", this.txId);
199 req.put("detail", true);
201 Type listType = new ParameterizedTypeImpl(List.class, new Class[]{Transaction.class});
202 List<Transaction> transactionList = client.request("list-transactions", req, listType);
204 logger.info("list-transactions:");
205 logger.info("size of transactionList:" + transactionList.size());
206 logger.info("all transactions:");
207 for (int i = 0; i < transactionList.size(); i++) {
208 logger.info(transactionList.get(i).toJson());
211 return transactionList;
214 public List<Transaction> listByAccountId(Client client) throws BytomException {
215 Map<String, Object> req = new HashMap<String, Object>();
216 req.put("account_id", this.accountId);
218 Type listType = new ParameterizedTypeImpl(List.class, new Class[]{Transaction.class});
219 List<Transaction> transactionList = client.request("list-transactions", req, listType);
221 logger.info("list-transactions:");
222 logger.info("size of transactionList:" + transactionList.size());
223 logger.info("all transactions:");
224 for (int i = 0; i < transactionList.size(); i++) {
225 logger.info(transactionList.get(i).toJson());
228 return transactionList;
232 * call get-transaction api
236 * @throws BytomException
238 public Transaction get(Client client) throws BytomException {
239 Map<String, Object> req = new HashMap<String, Object>();
240 req.put("tx_id", this.txId);
242 Transaction transaction = client.request("get-transaction", req, Transaction.class);
244 logger.info("get-transaction:");
245 logger.info(transaction.toJson());
252 public static class SignerBuilder {
254 * call sign-transaction api
256 * Sends a transaction template to a remote password for signing.
259 * @param template a signed transaction template
262 * @throws BytomException
264 public Template sign(Client client, Template template,
265 String password) throws BytomException {
266 HashMap<String, Object> req = new HashMap<String, Object>();
267 req.put("transaction", template);
268 req.put("password", password);
270 Template templateResult = client.requestGet("sign-transaction", req, "transaction",
271 Transaction.Template.class);
273 logger.info("sign-transaction:");
274 logger.info(templateResult.toJson());
276 return templateResult;
282 * A single input included in a transaction.
284 public static class Input {
286 * The alias of the account transferring the asset (possibly null if the input is
287 * an issuance or an unspent output is specified).
289 @SerializedName("account_alias")
290 public String accountAlias;
293 * The id of the account transferring the asset (possibly null if the input is an
294 * issuance or an unspent output is specified).
296 @SerializedName("account_id")
297 public String accountId;
299 @SerializedName("address")
300 public String address;
303 * The number of units of the asset being issued or spent.
308 * The alias of the asset being issued or spent (possibly null).
310 @SerializedName("asset_alias")
311 public String assetAlias;
314 * The definition of the asset being issued or spent (possibly null).
316 @SerializedName("asset_definition")
317 public Map<String, Object> assetDefinition;
320 * The id of the asset being issued or spent.
322 @SerializedName("asset_id")
323 public String assetId;
326 * The id of the output consumed by this input. Null if the input is an issuance.
328 @SerializedName("spent_output_id")
329 public String spentOutputId;
332 * The type of the input.<br>
333 * Possible values are "issue" and "spend".
337 public String arbitrary;
339 @SerializedName("control_program")
340 public String controlProgram;
345 * A single output included in a transaction.
347 public static class Output {
349 * The id of the output.
351 @SerializedName("id")
355 * The type the output.<br>
356 * Possible values are "control" and "retire".
361 * The output's position in a transaction's list of outputs.
366 * The control program which must be satisfied to transfer this output.
368 @SerializedName("control_program")
369 public String controlProgram;
372 * The id of the asset being controlled.
374 @SerializedName("asset_id")
375 public String assetId;
378 * The alias of the asset being controlled.
380 @SerializedName("asset_alias")
381 public String assetAlias;
384 * The definition of the asset being controlled (possibly null).
386 @SerializedName("asset_definition")
387 public Map<String, Object> assetDefinition;
390 * The number of units of the asset being controlled.
395 * The id of the account controlling this output (possibly null if a control
396 * program is specified).
398 @SerializedName("account_id")
399 public String accountId;
402 * The alias of the account controlling this output (possibly null if a control
403 * program is specified).
405 @SerializedName("account_alias")
406 public String accountAlias;
408 @SerializedName("address")
409 public String address;
414 * Base class representing actions that can be taken within a transaction.
416 public static class Action extends HashMap<String, Object> {
420 private static final long serialVersionUID = 7948250382060074590L;
423 * Default constructor initializes list and sets the client token.
426 // Several action types require client_token as an idempotency key.
427 // It's safest to include a default value for this param.
428 this.put("client_token", UUID.randomUUID().toString());
432 * Represents an issuance action.
434 public static class Issue extends Action {
438 private static final long serialVersionUID = -6296543909434749786L;
441 * Default constructor defines the action type as "issue"
444 this.put("type", "issue");
448 * Specifies the asset to be issued using its alias.<br>
449 * <strong>Either this or {@link Issue#setAssetId(String)} must be
451 * @param alias alias of the asset to be issued
452 * @return updated action object
454 public Issue setAssetAlias(String alias) {
455 this.put("asset_alias", alias);
460 * Specifies the asset to be issued using its id.<br>
461 * <strong>Either this or {@link Issue#setAssetAlias(String)} must be
463 * @param id id of the asset to be issued
464 * @return updated action object
466 public Issue setAssetId(String id) {
467 this.put("asset_id", id);
472 * Specifies the amount of the asset to be issued.<br>
473 * <strong>Must be called.</strong>
474 * @param amount number of units of the asset to be issued
475 * @return updated action object
477 public Issue setAmount(long amount) {
478 this.put("amount", amount);
484 * Represents a spend action taken on a particular account.
486 public static class SpendFromAccount extends Action {
490 private static final long serialVersionUID = 6444162327409625893L;
493 * Default constructor defines the action type as "spend_account"
495 public SpendFromAccount() {
496 this.put("type", "spend_account");
500 * Specifies the spending account using its alias.<br>
501 * <strong>Either this or {@link SpendFromAccount#setAccountId(String)} must
502 * be called.</strong><br>
503 * <strong>Must be used with {@link SpendFromAccount#setAssetAlias(String)}
505 * @param alias alias of the spending account
506 * @return updated action object
508 public SpendFromAccount setAccountAlias(String alias) {
509 this.put("account_alias", alias);
514 * Specifies the spending account using its id.<br>
515 * <strong>Either this or {@link SpendFromAccount#setAccountAlias(String)}
516 * must be called.</strong><br>
517 * <strong>Must be used with {@link SpendFromAccount#setAssetId(String)}
519 * @param id id of the spending account
520 * @return updated action object
522 public SpendFromAccount setAccountId(String id) {
523 this.put("account_id", id);
528 * Specifies the asset to be spent using its alias.<br>
529 * <strong>Either this or {@link SpendFromAccount#setAssetId(String)} must be
530 * called.</strong><br>
531 * <strong>Must be used with {@link SpendFromAccount#setAccountAlias(String)}
533 * @param alias alias of the asset to be spent
534 * @return updated action object
536 public SpendFromAccount setAssetAlias(String alias) {
537 this.put("asset_alias", alias);
542 * Specifies the asset to be spent using its id.<br>
543 * <strong>Either this or {@link SpendFromAccount#setAssetAlias(String)} must
544 * be called.</strong><br>
545 * <strong>Must be used with {@link SpendFromAccount#setAccountId(String)}
547 * @param id id of the asset to be spent
548 * @return updated action object
550 public SpendFromAccount setAssetId(String id) {
551 this.put("asset_id", id);
556 * Specifies the amount of asset to be spent.<br>
557 * <strong>Must be called.</strong>
558 * @param amount number of units of the asset to be spent
559 * @return updated action object
561 public SpendFromAccount setAmount(long amount) {
562 this.put("amount", amount);
568 * Represents a control action taken on a particular account.
570 public static class ControlWithAccount extends Action {
574 private static final long serialVersionUID = -1067464339402520620L;
577 * Default constructor defines the action type as "control_account"
579 public ControlWithAccount() {
580 this.put("type", "control_account");
584 * Specifies the controlling account using its alias.<br>
585 * <strong>Either this or {@link ControlWithAccount#setAccountId(String)} must
586 * be called.</strong><br>
587 * <strong>Must be used with {@link ControlWithAccount#setAssetAlias(String)}
589 * @param alias alias of the controlling account
590 * @return updated action object
592 public ControlWithAccount setAccountAlias(String alias) {
593 this.put("account_alias", alias);
598 * Specifies the controlling account using its id.<br>
599 * <strong>Either this or {@link ControlWithAccount#setAccountAlias(String)}
600 * must be called.</strong><br>
601 * <strong>Must be used with {@link ControlWithAccount#setAssetId(String)}
603 * @param id id of the controlling account
604 * @return updated action object
606 public ControlWithAccount setAccountId(String id) {
607 this.put("account_id", id);
612 * Specifies the asset to be controlled using its alias.<br>
613 * <strong>Either this or {@link ControlWithAccount#setAssetId(String)} must
614 * be called.</strong><br>
615 * <strong>Must be used with
616 * {@link ControlWithAccount#setAccountAlias(String)}.</strong>
617 * @param alias alias of the asset to be controlled
618 * @return updated action object
620 public ControlWithAccount setAssetAlias(String alias) {
621 this.put("asset_alias", alias);
626 * Specifies the asset to be controlled using its id.<br>
627 * <strong>Either this or {@link ControlWithAccount#setAssetAlias(String)}
628 * must be called.</strong><br>
629 * <strong>Must be used with {@link ControlWithAccount#setAccountId(String)}
631 * @param id id of the asset to be controlled
632 * @return updated action object
634 public ControlWithAccount setAssetId(String id) {
635 this.put("asset_id", id);
640 * Specifies the amount of the asset to be controlled.<br>
641 * <strong>Must be called.</strong>
642 * @param amount number of units of the asset to be controlled
643 * @return updated action object
645 public ControlWithAccount setAmount(long amount) {
646 this.put("amount", amount);
653 * Represents a control action taken on a particular address.
655 public static class ControlWithAddress extends Action {
659 private static final long serialVersionUID = 1292007349260961499L;
662 * Default constructor defines the action type as "control_address"
664 public ControlWithAddress() {
665 this.put("type", "control_address");
668 public ControlWithAddress setAddress(String address) {
669 this.put("address", address);
674 * Specifies the asset to be controlled using its alias.<br>
675 * <strong>Either this or {@link ControlWithAddress#setAssetId(String)} must
676 * be called.</strong><br>
677 * @param alias alias of the asset to be controlled
678 * @return updated action object
680 public ControlWithAddress setAssetAlias(String alias) {
681 this.put("asset_alias", alias);
686 * Specifies the asset to be controlled using its id.<br>
687 * <strong>Either this or {@link ControlWithAccount#setAssetAlias(String)}
688 * must be called.</strong><br>
689 * @param id id of the asset to be controlled
690 * @return updated action object
692 public ControlWithAddress setAssetId(String id) {
693 this.put("asset_id", id);
698 * Specifies the amount of the asset to be controlled.<br>
699 * <strong>Must be called.</strong>
700 * @param amount number of units of the asset to be controlled
701 * @return updated action object
703 public ControlWithAddress setAmount(long amount) {
704 this.put("amount", amount);
711 * Use this action to pay assets into a {@link Receiver}.
713 public static class ControlWithReceiver extends Action {
717 private static final long serialVersionUID = 7280759134960453401L;
720 * Default constructor.
722 public ControlWithReceiver() {
723 this.put("type", "control_receiver");
727 * Specifies the receiver that is being paid to.
729 * @param receiver the receiver being paid to
730 * @return this ControlWithReceiver object
732 public ControlWithReceiver setReceiver(Receiver receiver) {
733 this.put("receiver", receiver);
738 * Specifies the asset to be controlled using its alias.
740 * <strong>Either this or {@link ControlWithReceiver#setAssetId(String)} must
741 * be called.</strong>
742 * @param alias unique alias of the asset to be controlled
743 * @return this ControlWithReceiver object
745 public ControlWithReceiver setAssetAlias(String alias) {
746 this.put("asset_alias", alias);
751 * Specifies the asset to be controlled using its id.
753 * <strong>Either this or {@link ControlWithReceiver#setAssetAlias(String)}
754 * must be called.</strong>
755 * @param id unique ID of the asset to be controlled
756 * @return this ControlWithReceiver object
758 public ControlWithReceiver setAssetId(String id) {
759 this.put("asset_id", id);
764 * Specifies the amount of the asset to be controlled.
766 * <strong>Must be called.</strong>
767 * @param amount the number of units of the asset to be controlled
768 * @return this ControlWithReceiver object
770 public ControlWithReceiver setAmount(long amount) {
771 this.put("amount", amount);
778 * Represents a retire action.
780 public static class Retire extends Action {
784 private static final long serialVersionUID = -8434272436211832706L;
787 * Default constructor defines the action type as "control_program"
790 this.put("type", "retire");
794 * Specifies the amount of the asset to be retired.<br>
795 * <strong>Must be called.</strong>
796 * @param amount number of units of the asset to be retired
797 * @return updated action object
799 public Retire setAmount(long amount) {
800 this.put("amount", amount);
805 * Specifies the asset to be retired using its alias.<br>
806 * <strong>Either this or {@link Retire#setAssetId(String)} must be
808 * @param alias alias of the asset to be retired
809 * @return updated action object
811 public Retire setAssetAlias(String alias) {
812 this.put("asset_alias", alias);
817 * Specifies the asset to be retired using its id.<br>
818 * <strong>Either this or {@link Retire#setAssetAlias(String)} must be
820 * @param id id of the asset to be retired
821 * @return updated action object
823 public Retire setAssetId(String id) {
824 this.put("asset_id", id);
828 * @param arbitrary message to be on the chain (must be hexadecimal)
829 * @return updated action object
831 public Retire setArbitrary(String arbitrary){
832 this.put("arbitrary",arbitrary);
835 public Retire setAccountAlias(String alias) {
836 this.put("account_alias", alias);
840 public Retire setAccountId(String id) {
841 this.put("account_id", id);
848 * Sets a k,v parameter pair.
849 * @param key the key on the parameter object
850 * @param value the corresponding value
851 * @return updated action object
853 public Action setParameter(String key, Object value) {
854 this.put(key, value);
859 public static class Template {
861 * A hex-encoded representation of a transaction template.
863 @SerializedName("raw_transaction")
864 public String rawTransaction;
867 * The list of signing instructions for inputs in the transaction.
869 @SerializedName("signing_instructions")
870 public List<SigningInstruction> signingInstructions;
875 @SerializedName("local")
876 private boolean local;
879 * False (the default) makes the transaction "final" when signing, preventing
880 * further changes - the signature program commits to the transaction's signature
881 * hash. True makes the transaction extensible, committing only to the elements in
882 * the transaction so far, permitting the addition of new elements.
884 @SerializedName("allow_additional_actions")
885 private boolean allowAdditionalActions;
888 * allowAdditionalActions causes the transaction to be signed so that it can be
889 * used as a base transaction in a multiparty trade flow. To enable this setting,
890 * call this method after building the transaction, but before sending it to the
893 * All participants in a multiparty trade flow should call this method except for
894 * the last signer. Do not call this option if the transaction is complete, i.e.
895 * if it will not be used as a base transaction.
896 * @return updated transaction template
898 public Template allowAdditionalActions() {
899 this.allowAdditionalActions = true;
904 * A single signing instruction included in a transaction template.
906 public static class SigningInstruction {
908 * The input's position in a transaction's list of inputs.
913 * A list of components used to coordinate the signing of an input.
915 @SerializedName("witness_components")
916 public WitnessComponent[] witnessComponents;
920 * A single witness component, holding information that will become the input
923 public static class WitnessComponent {
925 * The type of witness component.<br>
926 * Possible types are "data" and "raw_tx_signature".
931 * Data to be included in the input witness (null unless type is "data").
936 * The number of signatures required for an input (null unless type is
942 * The list of keys to sign with (null unless type is "signature").
947 * The list of signatures made with the specified keys (null unless type is
950 public String[] signatures;
954 * A class representing a derived signing key.
956 public static class KeyID {
958 * The extended public key associated with the private key used to sign.
963 * The derivation path of the extended public key.
965 @SerializedName("derivation_path")
966 public String[] derivationPath;
970 * Serializes the Address into a form that is safe to transfer over the wire.
972 * @return the JSON-serialized representation of the Receiver object
974 public String toJson() {
975 return Utils.serializer.toJson(this);
980 public static class SubmitResponse {
982 * The transaction id.
986 public String toJson() {
987 return Utils.serializer.toJson(this);
993 * Call submit-transaction api
998 * @throws BytomException
1000 public static SubmitResponse submit(Client client, Template template)
1001 throws BytomException {
1002 HashMap<String, Object> body = new HashMap<>();
1003 body.put("raw_transaction", template.rawTransaction);
1004 return client.request("submit-transaction", body, SubmitResponse.class);
1007 public static class TransactionGas {
1009 * total consumed neu(1BTM = 10^8NEU) for execute transaction.
1011 @SerializedName("total_neu")
1012 public int totalNeu;
1015 * consumed neu for storage transaction .
1017 @SerializedName("storage_neu")
1018 public int storageNeu;
1020 * consumed neu for execute VM.
1022 @SerializedName("vm_neu")
1027 * call estimate-transaction-gas api
1032 * @throws BytomException
1034 public static TransactionGas estimateGas(Client client, Template template)
1035 throws BytomException {
1036 HashMap<String, Object> body = new HashMap<>();
1037 body.put("transaction_template", template);
1038 return client.request("estimate-transaction-gas", body, TransactionGas.class);
1041 public static class Feed {
1043 * name of the transaction feed.
1045 public String alias;
1047 * filter, filter of the transaction feed.
1049 public String filter;
1052 * param, param of the transaction feed.
1054 public TransactionFeedParam param;
1056 private static Logger logger = Logger.getLogger(Transaction.class);
1059 * Serializes the TransactionFeed into a form that is safe to transfer over the wire.
1061 * @return the JSON-serialized representation of the TransactionFeed object
1063 public String toJson() {
1064 return Utils.serializer.toJson(this);
1067 public static class Builder {
1069 public String alias;
1071 public String filter;
1076 public Builder setAlias(String alias) {
1081 public Builder setFilter(String filter) {
1082 this.filter = filter;
1087 * Call create-transaction-feed api
1090 * @throws BytomException
1092 public void create(Client client) throws BytomException {
1093 client.request("create-transaction-feed", this);
1094 logger.info("create-transaction-feed");
1099 * Call get-transaction-feed api
1104 * @throws BytomException
1106 public static Feed getByAlias(Client client, String alias) throws BytomException {
1107 Map<String, Object> req = new HashMap<String, Object>();
1108 req.put("alias", alias);
1110 // the return param contains txfeed.
1111 Feed transactionFeed = client.requestGet("get-transaction-feed",
1112 req, "txfeed", Feed.class);
1113 logger.info("get-transaction-feed.");
1114 logger.info(transactionFeed.toJson());
1116 return transactionFeed;
1120 * Call update-transaction-feed api
1125 * @throws BytomException
1127 public static void update(Client client, String alias, String filter) throws BytomException {
1128 Map<String, Object> req = new HashMap<String, Object>();
1129 req.put("alias", alias);
1130 req.put("filter", filter);
1131 client.request("update-transaction-feed", req);
1132 logger.info("update-transaction-feed successfully");
1136 * Call list-transaction-feeds api
1139 * @throws BytomException
1141 public static List<Feed> list(Client client) throws BytomException {
1143 Type listType = new ParameterizedTypeImpl(List.class, new Class[]{Feed.class});
1144 List<Feed> transactionFeedList = client.request("list-transaction-feeds", null, listType);
1146 logger.info("list-transaction-feeds:");
1147 logger.info("size of transactionList:" + transactionFeedList.size());
1148 for (int i =0 ;i < transactionFeedList.size();i++) {
1149 logger.info(transactionFeedList.get(i).toJson());
1151 return transactionFeedList;
1155 * Call delete-transaction-feed api
1159 * @throws BytomException
1161 public static void deleteByAlias(Client client, String alias) throws BytomException {
1162 Map<String, Object> req = new HashMap<String, Object>();
1163 req.put("alias", alias);
1164 client.request("delete-transaction-feed", req);
1165 logger.info("delete-transaction-feed successfully");
1170 public class TransactionFeedParam {
1175 public String assetid;
1180 public long lowerlimit;
1185 public long upperlimit;