forked from Qortal/qortal
Merge pull request #181 from kennycud/master
Foreign Coin Trade Fees & Summaries
This commit is contained in:
commit
f6b91df7b6
@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.qortal.api.ApiError;
|
||||
import org.qortal.api.ApiErrors;
|
||||
@ -265,4 +266,117 @@ public class CrossChainBitcoinResource {
|
||||
|
||||
return CrossChainUtils.buildServerConfigurationInfo(Bitcoin.getInstance());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feekb")
|
||||
@Operation(
|
||||
summary = "Returns Bitcoin fee per Kb.",
|
||||
description = "Returns Bitcoin fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getBitcoinFeePerKb() {
|
||||
Bitcoin bitcoin = Bitcoin.getInstance();
|
||||
|
||||
return String.valueOf(bitcoin.getFeePerKb().value);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeekb")
|
||||
@Operation(
|
||||
summary = "Sets Bitcoin fee per Kb.",
|
||||
description = "Sets Bitcoin fee per Kb.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee per Kb",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setBitcoinFeePerKb(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Bitcoin bitcoin = Bitcoin.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeePerKb(bitcoin, fee);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feeceiling")
|
||||
@Operation(
|
||||
summary = "Returns Bitcoin fee per Kb.",
|
||||
description = "Returns Bitcoin fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getBitcoinFeeCeiling() {
|
||||
Bitcoin bitcoin = Bitcoin.getInstance();
|
||||
|
||||
return String.valueOf(bitcoin.getFeeCeiling());
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeeceiling")
|
||||
@Operation(
|
||||
summary = "Sets Bitcoin fee ceiling.",
|
||||
description = "Sets Bitcoin fee ceiling.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setBitcoinFeeCeiling(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Bitcoin bitcoin = Bitcoin.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeeCeiling(bitcoin, fee);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,4 +265,117 @@ public class CrossChainDigibyteResource {
|
||||
|
||||
return CrossChainUtils.buildServerConfigurationInfo(Digibyte.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feekb")
|
||||
@Operation(
|
||||
summary = "Returns Digibyte fee per Kb.",
|
||||
description = "Returns Digibyte fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getDigibyteFeePerKb() {
|
||||
Digibyte digibyte = Digibyte.getInstance();
|
||||
|
||||
return String.valueOf(digibyte.getFeePerKb().value);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeekb")
|
||||
@Operation(
|
||||
summary = "Sets Digibyte fee per Kb.",
|
||||
description = "Sets Digibyte fee per Kb.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee per Kb",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setDigibyteFeePerKb(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Digibyte digibyte = Digibyte.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeePerKb(digibyte, fee);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feeceiling")
|
||||
@Operation(
|
||||
summary = "Returns Digibyte fee per Kb.",
|
||||
description = "Returns Digibyte fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getDigibyteFeeCeiling() {
|
||||
Digibyte digibyte = Digibyte.getInstance();
|
||||
|
||||
return String.valueOf(digibyte.getFeeCeiling());
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeeceiling")
|
||||
@Operation(
|
||||
summary = "Sets Digibyte fee ceiling.",
|
||||
description = "Sets Digibyte fee ceiling.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setDigibyteFeeCeiling(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Digibyte digibyte = Digibyte.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeeCeiling(digibyte, fee);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
}
|
@ -265,4 +265,117 @@ public class CrossChainDogecoinResource {
|
||||
|
||||
return CrossChainUtils.buildServerConfigurationInfo(Dogecoin.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feekb")
|
||||
@Operation(
|
||||
summary = "Returns Dogecoin fee per Kb.",
|
||||
description = "Returns Dogecoin fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getDogecoinFeePerKb() {
|
||||
Dogecoin dogecoin = Dogecoin.getInstance();
|
||||
|
||||
return String.valueOf(dogecoin.getFeePerKb().value);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeekb")
|
||||
@Operation(
|
||||
summary = "Sets Dogecoin fee per Kb.",
|
||||
description = "Sets Dogecoin fee per Kb.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee per Kb",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setDogecoinFeePerKb(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Dogecoin dogecoin = Dogecoin.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeePerKb(dogecoin, fee);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feeceiling")
|
||||
@Operation(
|
||||
summary = "Returns Dogecoin fee per Kb.",
|
||||
description = "Returns Dogecoin fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getDogecoinFeeCeiling() {
|
||||
Dogecoin dogecoin = Dogecoin.getInstance();
|
||||
|
||||
return String.valueOf(dogecoin.getFeeCeiling());
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeeceiling")
|
||||
@Operation(
|
||||
summary = "Sets Dogecoin fee ceiling.",
|
||||
description = "Sets Dogecoin fee ceiling.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setDogecoinFeeCeiling(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Dogecoin dogecoin = Dogecoin.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeeCeiling(dogecoin, fee);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
}
|
@ -304,4 +304,117 @@ public class CrossChainLitecoinResource {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feekb")
|
||||
@Operation(
|
||||
summary = "Returns Litecoin fee per Kb.",
|
||||
description = "Returns Litecoin fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getLitecoinFeePerKb() {
|
||||
Litecoin litecoin = Litecoin.getInstance();
|
||||
|
||||
return String.valueOf(litecoin.getFeePerKb().value);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeekb")
|
||||
@Operation(
|
||||
summary = "Sets Litecoin fee per Kb.",
|
||||
description = "Sets Litecoin fee per Kb.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee per Kb",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setLitecoinFeePerKb(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Litecoin litecoin = Litecoin.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeePerKb(litecoin, fee);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feeceiling")
|
||||
@Operation(
|
||||
summary = "Returns Litecoin fee per Kb.",
|
||||
description = "Returns Litecoin fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getLitecoinFeeCeiling() {
|
||||
Litecoin litecoin = Litecoin.getInstance();
|
||||
|
||||
return String.valueOf(litecoin.getFeeCeiling());
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeeceiling")
|
||||
@Operation(
|
||||
summary = "Sets Litecoin fee ceiling.",
|
||||
description = "Sets Litecoin fee ceiling.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setLitecoinFeeCeiling(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Litecoin litecoin = Litecoin.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeeCeiling(litecoin, fee);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
}
|
@ -351,4 +351,117 @@ public class CrossChainPirateChainResource {
|
||||
|
||||
return CrossChainUtils.buildServerConfigurationInfo(PirateChain.getInstance());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feekb")
|
||||
@Operation(
|
||||
summary = "Returns PirateChain fee per Kb.",
|
||||
description = "Returns PirateChain fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getPirateChainFeePerKb() {
|
||||
PirateChain pirateChain = PirateChain.getInstance();
|
||||
|
||||
return String.valueOf(pirateChain.getFeePerKb().value);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeekb")
|
||||
@Operation(
|
||||
summary = "Sets PirateChain fee per Kb.",
|
||||
description = "Sets PirateChain fee per Kb.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee per Kb",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setPirateChainFeePerKb(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
PirateChain pirateChain = PirateChain.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeePerKb(pirateChain, fee);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feeceiling")
|
||||
@Operation(
|
||||
summary = "Returns PirateChain fee per Kb.",
|
||||
description = "Returns PirateChain fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getPirateChainFeeCeiling() {
|
||||
PirateChain pirateChain = PirateChain.getInstance();
|
||||
|
||||
return String.valueOf(pirateChain.getFeeCeiling());
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeeceiling")
|
||||
@Operation(
|
||||
summary = "Sets PirateChain fee ceiling.",
|
||||
description = "Sets PirateChain fee ceiling.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setPirateChainFeeCeiling(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
PirateChain pirateChain = PirateChain.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeeCeiling(pirateChain, fee);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,4 +265,117 @@ public class CrossChainRavencoinResource {
|
||||
|
||||
return CrossChainUtils.buildServerConfigurationInfo(Ravencoin.getInstance());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feekb")
|
||||
@Operation(
|
||||
summary = "Returns Ravencoin fee per Kb.",
|
||||
description = "Returns Ravencoin fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getRavencoinFeePerKb() {
|
||||
Ravencoin ravencoin = Ravencoin.getInstance();
|
||||
|
||||
return String.valueOf(ravencoin.getFeePerKb().value);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeekb")
|
||||
@Operation(
|
||||
summary = "Sets Ravencoin fee per Kb.",
|
||||
description = "Sets Ravencoin fee per Kb.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee per Kb",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setRavencoinFeePerKb(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Ravencoin ravencoin = Ravencoin.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeePerKb(ravencoin, fee);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/feeceiling")
|
||||
@Operation(
|
||||
summary = "Returns Ravencoin fee per Kb.",
|
||||
description = "Returns Ravencoin fee per Kb.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
schema = @Schema(
|
||||
type = "number"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
public String getRavencoinFeeCeiling() {
|
||||
Ravencoin ravencoin = Ravencoin.getInstance();
|
||||
|
||||
return String.valueOf(ravencoin.getFeeCeiling());
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/updatefeeceiling")
|
||||
@Operation(
|
||||
summary = "Sets Ravencoin fee ceiling.",
|
||||
description = "Sets Ravencoin fee ceiling.",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "number",
|
||||
description = "the fee",
|
||||
example = "100"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "number", description = "fee"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.INVALID_CRITERIA})
|
||||
public String setRavencoinFeeCeiling(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String fee) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
Ravencoin ravencoin = Ravencoin.getInstance();
|
||||
|
||||
try {
|
||||
return CrossChainUtils.setFeeCeiling(ravencoin, fee);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,14 @@ import org.qortal.api.model.CrossChainTradeSummary;
|
||||
import org.qortal.controller.tradebot.TradeBot;
|
||||
import org.qortal.crosschain.ACCT;
|
||||
import org.qortal.crosschain.AcctMode;
|
||||
import org.qortal.crosschain.Bitcoiny;
|
||||
import org.qortal.crosschain.ForeignBlockchainException;
|
||||
import org.qortal.crosschain.SupportedBlockchain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.at.ATData;
|
||||
import org.qortal.data.at.ATStateData;
|
||||
import org.qortal.data.crosschain.CrossChainTradeData;
|
||||
import org.qortal.data.crosschain.TransactionSummary;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.MessageTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -47,6 +50,7 @@ import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Path("/crosschain")
|
||||
@Tag(name = "Cross-Chain")
|
||||
@ -497,6 +501,111 @@ public class CrossChainResource {
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/p2sh")
|
||||
@Operation(
|
||||
summary = "Returns P2SH Address",
|
||||
description = "Get the P2SH address to lock foreign coin in a cross chain trade for QORT",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "string",
|
||||
description = "the AT address",
|
||||
example = "AKFnu9yBp7tUAc5HAphhfCxRZTYoeKXgUy"
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string", description = "address"))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.ADDRESS_UNKNOWN, ApiError.INVALID_CRITERIA})
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public String getForeignP2SH(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String atAddress) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
ATData atData = repository.getATRepository().fromATAddress(atAddress);
|
||||
if (atData == null)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.ADDRESS_UNKNOWN);
|
||||
|
||||
ACCT acct = SupportedBlockchain.getAcctByCodeHash(atData.getCodeHash());
|
||||
|
||||
if( acct == null || !(acct.getBlockchain() instanceof Bitcoiny) )
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
|
||||
Bitcoiny bitcoiny = (Bitcoiny) acct.getBlockchain();
|
||||
|
||||
CrossChainTradeData crossChainTradeData = acct.populateTradeData(repository, atData);
|
||||
|
||||
Optional<String> p2sh
|
||||
= CrossChainUtils.getP2ShAddressForAT(atAddress, repository, bitcoiny, crossChainTradeData);
|
||||
|
||||
if(p2sh.isPresent()){
|
||||
return p2sh.get();
|
||||
}
|
||||
else{
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.ADDRESS_UNKNOWN);
|
||||
}
|
||||
}
|
||||
catch (DataException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.REPOSITORY_ISSUE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/txactivity")
|
||||
@Operation(
|
||||
summary = "Returns Foreign Transaction Activity",
|
||||
description = "Get the activity related to foreign coin trading",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
content = @Content(
|
||||
array = @ArraySchema(
|
||||
schema = @Schema(
|
||||
implementation = TransactionSummary.class
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_CRITERIA, ApiError.REPOSITORY_ISSUE, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE})
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public List<TransactionSummary> getForeignTransactionActivity(@HeaderParam(Security.API_KEY_HEADER) String apiKey, @Parameter(
|
||||
description = "Limit to specific blockchain",
|
||||
example = "LITECOIN",
|
||||
schema = @Schema(implementation = SupportedBlockchain.class)
|
||||
) @QueryParam("foreignBlockchain") SupportedBlockchain foreignBlockchain) {
|
||||
Security.checkApiCallAllowed(request);
|
||||
|
||||
if (!(foreignBlockchain.getInstance() instanceof Bitcoiny))
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
||||
|
||||
Bitcoiny bitcoiny = (Bitcoiny) foreignBlockchain.getInstance() ;
|
||||
|
||||
org.bitcoinj.core.Context.propagate( bitcoiny.getBitcoinjContext() );
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
|
||||
// sort from last lock to first lock
|
||||
return CrossChainUtils
|
||||
.getForeignTradeSummaries(foreignBlockchain, repository, bitcoiny).stream()
|
||||
.sorted(Comparator.comparing(TransactionSummary::getLockingTimestamp).reversed())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
catch (DataException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.REPOSITORY_ISSUE, e.getMessage());
|
||||
}
|
||||
catch (ForeignBlockchainException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private ATData fetchAtDataWithChecking(Repository repository, String atAddress) throws DataException {
|
||||
ATData atData = repository.getATRepository().fromATAddress(atAddress);
|
||||
if (atData == null)
|
||||
|
@ -2,11 +2,28 @@ package org.qortal.api.resource;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.ScriptBuilder;
|
||||
|
||||
import org.qortal.crosschain.*;
|
||||
import org.qortal.data.at.ATData;
|
||||
import org.qortal.data.crosschain.AtomicTransactionData;
|
||||
import org.qortal.data.crosschain.CrossChainTradeData;
|
||||
import org.qortal.data.crosschain.TradeBotData;
|
||||
import org.qortal.data.crosschain.TransactionSummary;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class CrossChainUtils {
|
||||
private static final Logger LOGGER = LogManager.getLogger(CrossChainUtils.class);
|
||||
@ -44,4 +61,360 @@ public class CrossChainUtils {
|
||||
|
||||
return infos;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fee Per Kb
|
||||
*
|
||||
* @param bitcoiny the blockchain support
|
||||
* @param fee the fee in satoshis
|
||||
*
|
||||
* @return the fee if valid
|
||||
*
|
||||
* @throws IllegalArgumentException if invalid
|
||||
*/
|
||||
public static String setFeePerKb(Bitcoiny bitcoiny, String fee) throws IllegalArgumentException {
|
||||
|
||||
long satoshis = Long.parseLong(fee);
|
||||
if( satoshis < 0 ) throw new IllegalArgumentException("can't set fee to negative number");
|
||||
|
||||
bitcoiny.setFeePerKb(Coin.valueOf(satoshis) );
|
||||
|
||||
return String.valueOf(bitcoiny.getFeePerKb().value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Fee Ceiling
|
||||
*
|
||||
* @param bitcoiny the blockchain support
|
||||
* @param fee the fee in satoshis
|
||||
*
|
||||
* @return the fee if valid
|
||||
*
|
||||
* @throws IllegalArgumentException if invalid
|
||||
*/
|
||||
public static String setFeeCeiling(Bitcoiny bitcoiny, String fee) throws IllegalArgumentException{
|
||||
|
||||
long satoshis = Long.parseLong(fee);
|
||||
if( satoshis < 0 ) throw new IllegalArgumentException("can't set fee to negative number");
|
||||
|
||||
bitcoiny.setFeeCeiling( Long.parseLong(fee));
|
||||
|
||||
return String.valueOf(bitcoiny.getFeeCeiling());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get P2Sh Address For AT
|
||||
*
|
||||
* @param atAddress the AT address
|
||||
* @param repository the repository
|
||||
* @param bitcoiny the blockchain data
|
||||
* @param crossChainTradeData the trade data
|
||||
*
|
||||
* @return the p2sh address for the trade, if there is one
|
||||
*
|
||||
* @throws DataException
|
||||
*/
|
||||
public static Optional<String> getP2ShAddressForAT(
|
||||
String atAddress,
|
||||
Repository repository,
|
||||
Bitcoiny bitcoiny,
|
||||
CrossChainTradeData crossChainTradeData) throws DataException {
|
||||
|
||||
// get the trade bot data for the AT address
|
||||
Optional<TradeBotData> tradeBotDataOptional
|
||||
= repository.getCrossChainRepository()
|
||||
.getAllTradeBotData().stream()
|
||||
.filter(data -> data.getAtAddress().equals(atAddress))
|
||||
.findFirst();
|
||||
|
||||
if( tradeBotDataOptional.isEmpty() )
|
||||
return Optional.empty();
|
||||
|
||||
TradeBotData tradeBotData = tradeBotDataOptional.get();
|
||||
|
||||
// return the p2sh address from the trade bot
|
||||
return getP2ShFromTradeBot(bitcoiny, crossChainTradeData, tradeBotData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Foreign Trade Summaries
|
||||
*
|
||||
* @param foreignBlockchain the blockchain traded on
|
||||
* @param repository the repository
|
||||
* @param bitcoiny data for the blockchain trade on
|
||||
* @return
|
||||
* @throws DataException
|
||||
* @throws ForeignBlockchainException
|
||||
*/
|
||||
public static List<TransactionSummary> getForeignTradeSummaries(
|
||||
SupportedBlockchain foreignBlockchain,
|
||||
Repository repository,
|
||||
Bitcoiny bitcoiny) throws DataException, ForeignBlockchainException {
|
||||
|
||||
// get all the AT address for the given blockchain
|
||||
List<String> atAddresses
|
||||
= repository.getCrossChainRepository().getAllTradeBotData().stream()
|
||||
.filter(data -> foreignBlockchain.name().toLowerCase().equals(data.getForeignBlockchain().toLowerCase()))
|
||||
//.filter( data -> data.getForeignKey().equals( xpriv )) // TODO
|
||||
.map(data -> data.getAtAddress())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<TransactionSummary> summaries = new ArrayList<>( atAddresses.size() * 2 );
|
||||
|
||||
// for each AT address, gather the data and get foreign trade summary
|
||||
for( String atAddress: atAddresses) {
|
||||
|
||||
ATData atData = repository.getATRepository().fromATAddress(atAddress);
|
||||
|
||||
CrossChainTradeData crossChainTradeData = foreignBlockchain.getLatestAcct().populateTradeData(repository, atData);
|
||||
|
||||
Optional<String> address = getP2ShAddressForAT(atAddress,repository, bitcoiny, crossChainTradeData);
|
||||
|
||||
if( address.isPresent()){
|
||||
summaries.add( getForeignTradeSummary( bitcoiny, address.get(), atAddress ) );
|
||||
}
|
||||
}
|
||||
|
||||
return summaries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get P2Sh From Trade Bot
|
||||
*
|
||||
* Get P2Sh address from the trade bot
|
||||
*
|
||||
* @param bitcoiny the blockchain for the trade
|
||||
* @param crossChainTradeData the cross cahin data for the trade
|
||||
* @param tradeBotData the data from the trade bot
|
||||
*
|
||||
* @return the address, original format
|
||||
*/
|
||||
private static Optional<String> getP2ShFromTradeBot(
|
||||
Bitcoiny bitcoiny,
|
||||
CrossChainTradeData crossChainTradeData,
|
||||
TradeBotData tradeBotData) {
|
||||
|
||||
// Pirate Chain does not support this
|
||||
if( SupportedBlockchain.PIRATECHAIN.name().equals(tradeBotData.getForeignBlockchain())) return Optional.empty();
|
||||
|
||||
// need to get the trade PKH from the trade bot
|
||||
if( tradeBotData.getTradeForeignPublicKeyHash() == null ) return Optional.empty();
|
||||
|
||||
// need to get the lock time from the trade bot
|
||||
if( tradeBotData.getLockTimeA() == null ) return Optional.empty();
|
||||
|
||||
// need to get the creator PKH from the trade bot
|
||||
if( crossChainTradeData.creatorForeignPKH == null ) return Optional.empty();
|
||||
|
||||
// need to get the secret from the trade bot
|
||||
if( tradeBotData.getHashOfSecret() == null ) return Optional.empty();
|
||||
|
||||
// if we have the necessary data from the trade bot,
|
||||
// then build the redeem script necessary to facilitate the trade
|
||||
byte[] redeemScriptBytes
|
||||
= BitcoinyHTLC.buildScript(
|
||||
tradeBotData.getTradeForeignPublicKeyHash(),
|
||||
tradeBotData.getLockTimeA(),
|
||||
crossChainTradeData.creatorForeignPKH,
|
||||
tradeBotData.getHashOfSecret()
|
||||
);
|
||||
|
||||
|
||||
String p2shAddress = bitcoiny.deriveP2shAddress(redeemScriptBytes);
|
||||
|
||||
return Optional.of(p2shAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Foreign Trade Summary
|
||||
*
|
||||
* @param bitcoiny the blockchain the trade occurred on
|
||||
* @param p2shAddress the p2sh address
|
||||
* @param atAddress the AT address the p2sh address is derived from
|
||||
*
|
||||
* @return the summary
|
||||
*
|
||||
* @throws ForeignBlockchainException
|
||||
*/
|
||||
public static TransactionSummary getForeignTradeSummary(Bitcoiny bitcoiny, String p2shAddress, String atAddress)
|
||||
throws ForeignBlockchainException {
|
||||
Script outputScript = ScriptBuilder.createOutputScript(
|
||||
Address.fromString(bitcoiny.getNetworkParameters(), p2shAddress));
|
||||
|
||||
List<TransactionHash> hashes
|
||||
= bitcoiny.getAddressTransactions( outputScript.getProgram(), true);
|
||||
|
||||
TransactionSummary summary;
|
||||
|
||||
if(hashes.isEmpty()){
|
||||
summary
|
||||
= new TransactionSummary(
|
||||
atAddress,
|
||||
p2shAddress,
|
||||
"N/A",
|
||||
"N/A",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"N/A",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
else if( hashes.size() == 1) {
|
||||
AtomicTransactionData data = buildTransactionData(bitcoiny, hashes.get(0));
|
||||
summary = new TransactionSummary(
|
||||
atAddress,
|
||||
p2shAddress,
|
||||
"N/A",
|
||||
data.hash.txHash,
|
||||
data.timestamp,
|
||||
data.totalAmount,
|
||||
getTotalInput(bitcoiny, data.inputs) - data.totalAmount,
|
||||
data.size,
|
||||
"N/A",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
// otherwise assuming there is 2 and only 2 hashes
|
||||
else {
|
||||
List<AtomicTransactionData> atomicTransactionDataList = new ArrayList<>(2);
|
||||
|
||||
// hashes -> data
|
||||
for( TransactionHash hash : hashes){
|
||||
atomicTransactionDataList.add(buildTransactionData(bitcoiny,hash));
|
||||
}
|
||||
|
||||
// sort the transaction data by time
|
||||
List<AtomicTransactionData> sorted
|
||||
= atomicTransactionDataList.stream()
|
||||
.sorted((data1, data2) -> data1.timestamp.compareTo(data2.timestamp))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// build the summary using the first 2 transactions
|
||||
summary = buildForeignTradeSummary(atAddress, p2shAddress, sorted.get(0), sorted.get(1), bitcoiny);
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Foreign Trade Summary
|
||||
*
|
||||
* @param p2shValue the p2sh address, original format
|
||||
* @param lockingTransaction the transaction lock the foreighn coin
|
||||
* @param unlockingTransaction the transaction to unlock the foreign coin
|
||||
* @param bitcoiny the blockchain the trade occurred on
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws ForeignBlockchainException
|
||||
*/
|
||||
private static TransactionSummary buildForeignTradeSummary(
|
||||
String atAddress,
|
||||
String p2shValue,
|
||||
AtomicTransactionData lockingTransaction,
|
||||
AtomicTransactionData unlockingTransaction,
|
||||
Bitcoiny bitcoiny) throws ForeignBlockchainException {
|
||||
|
||||
// get sum of the relevant inputs for each transaction
|
||||
long lockingTotalInput = getTotalInput(bitcoiny, lockingTransaction.inputs);
|
||||
long unlockingTotalInput = getTotalInput(bitcoiny, unlockingTransaction.inputs);
|
||||
|
||||
// find the address that has output that matches the total input
|
||||
Optional<Map.Entry<List<String>, Long>> addressValue
|
||||
= lockingTransaction.valueByAddress.entrySet().stream()
|
||||
.filter(entry -> entry.getValue() == unlockingTotalInput).findFirst();
|
||||
|
||||
// set that matching address, if found
|
||||
String p2shAddress;
|
||||
if( addressValue.isPresent() && addressValue.get().getKey().size() == 1 ){
|
||||
p2shAddress = addressValue.get().getKey().get(0);
|
||||
}
|
||||
else {
|
||||
p2shAddress = "N/A";
|
||||
}
|
||||
|
||||
// build summaries with prepared values
|
||||
// the fees are the total amount subtracted by the total transaction input
|
||||
return new TransactionSummary(
|
||||
atAddress,
|
||||
p2shValue,
|
||||
p2shAddress,
|
||||
lockingTransaction.hash.txHash,
|
||||
lockingTransaction.timestamp,
|
||||
lockingTransaction.totalAmount,
|
||||
lockingTotalInput - lockingTransaction.totalAmount,
|
||||
lockingTransaction.size,
|
||||
unlockingTransaction.hash.txHash,
|
||||
unlockingTransaction.timestamp,
|
||||
unlockingTransaction.totalAmount,
|
||||
unlockingTotalInput - unlockingTransaction.totalAmount,
|
||||
unlockingTransaction.size
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Transaction Data
|
||||
*
|
||||
* @param bitcoiny the coin for the transaction
|
||||
* @param hash the hash for the transaction
|
||||
*
|
||||
* @return the data for the transaction
|
||||
*
|
||||
* @throws ForeignBlockchainException
|
||||
*/
|
||||
private static AtomicTransactionData buildTransactionData( Bitcoiny bitcoiny, TransactionHash hash)
|
||||
throws ForeignBlockchainException {
|
||||
|
||||
BitcoinyTransaction transaction = bitcoiny.getTransaction(hash.txHash);
|
||||
|
||||
// destination address list -> value
|
||||
Map<List<String>, Long> valueByAddress = new HashMap<>();
|
||||
|
||||
// for each output in the transaction, index by address list
|
||||
for( BitcoinyTransaction.Output output : transaction.outputs) {
|
||||
valueByAddress.put(output.addresses, output.value);
|
||||
}
|
||||
|
||||
return new AtomicTransactionData(
|
||||
hash,
|
||||
transaction.timestamp,
|
||||
transaction.inputs,
|
||||
valueByAddress,
|
||||
transaction.totalAmount,
|
||||
transaction.size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Total Input
|
||||
*
|
||||
* Get the sum of all the inputs used in a list of inputs.
|
||||
*
|
||||
* @param bitcoiny the coin the inputs belong to
|
||||
* @param inputs the inputs
|
||||
*
|
||||
* @return the sum
|
||||
*
|
||||
* @throws ForeignBlockchainException
|
||||
*/
|
||||
private static long getTotalInput(Bitcoiny bitcoiny, List<BitcoinyTransaction.Input> inputs)
|
||||
throws ForeignBlockchainException {
|
||||
|
||||
long totalInputOut = 0;
|
||||
|
||||
// for each input, add to total input,
|
||||
// get the indexed transaction output value and add to total value
|
||||
for( BitcoinyTransaction.Input input : inputs){
|
||||
|
||||
BitcoinyTransaction inputOut = bitcoiny.getTransaction(input.outputTxHash);
|
||||
BitcoinyTransaction.Output output = inputOut.outputs.get(input.outputVout);
|
||||
totalInputOut += output.value;
|
||||
}
|
||||
return totalInputOut;
|
||||
}
|
||||
}
|
@ -22,8 +22,6 @@ public class Bitcoin extends Bitcoiny {
|
||||
private static final long MINIMUM_ORDER_AMOUNT = 100000; // 0.001 BTC minimum order, due to high fees
|
||||
|
||||
// Temporary values until a dynamic fee system is written.
|
||||
private static final long OLD_FEE_AMOUNT = 4_000L; // Not 5000 so that existing P2SH-B can output 1000, avoiding dust issue, leaving 4000 for fees.
|
||||
private static final long NEW_FEE_TIMESTAMP = 1598280000000L; // milliseconds since epoch
|
||||
private static final long NEW_FEE_AMOUNT = 6_000L;
|
||||
|
||||
private static final long NON_MAINNET_FEE = 1000L; // enough for TESTNET3 and should be OK for REGTEST
|
||||
@ -113,11 +111,7 @@ public class Bitcoin extends Bitcoiny {
|
||||
|
||||
@Override
|
||||
public long getP2shFee(Long timestamp) {
|
||||
// TODO: This will need to be replaced with something better in the near future!
|
||||
if (timestamp != null && timestamp < NEW_FEE_TIMESTAMP)
|
||||
return OLD_FEE_AMOUNT;
|
||||
|
||||
return NEW_FEE_AMOUNT;
|
||||
return this.getFeeCeiling();
|
||||
}
|
||||
},
|
||||
TEST3 {
|
||||
@ -179,6 +173,16 @@ public class Bitcoin extends Bitcoiny {
|
||||
}
|
||||
};
|
||||
|
||||
private long feeCeiling = NEW_FEE_AMOUNT;
|
||||
|
||||
public long getFeeCeiling() {
|
||||
return feeCeiling;
|
||||
}
|
||||
|
||||
public void setFeeCeiling(long feeCeiling) {
|
||||
this.feeCeiling = feeCeiling;
|
||||
}
|
||||
|
||||
public abstract NetworkParameters getParams();
|
||||
public abstract Collection<ElectrumX.Server> getServers();
|
||||
public abstract String getGenesisHash();
|
||||
@ -192,7 +196,7 @@ public class Bitcoin extends Bitcoiny {
|
||||
// Constructors and instance
|
||||
|
||||
private Bitcoin(BitcoinNet bitcoinNet, BitcoinyBlockchainProvider blockchain, Context bitcoinjContext, String currencyCode) {
|
||||
super(blockchain, bitcoinjContext, currencyCode);
|
||||
super(blockchain, bitcoinjContext, currencyCode, bitcoinjContext.getFeePerKb());
|
||||
this.bitcoinNet = bitcoinNet;
|
||||
|
||||
LOGGER.info(() -> String.format("Starting Bitcoin support using %s", this.bitcoinNet.name()));
|
||||
@ -237,6 +241,16 @@ public class Bitcoin extends Bitcoiny {
|
||||
return this.bitcoinNet.getP2shFee(timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFeeCeiling() {
|
||||
return this.bitcoinNet.getFeeCeiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFeeCeiling(long fee) {
|
||||
|
||||
this.bitcoinNet.setFeeCeiling( fee );
|
||||
}
|
||||
/**
|
||||
* Returns bitcoinj transaction sending <tt>amount</tt> to <tt>recipient</tt> using 20 sat/byte fee.
|
||||
*
|
||||
|
@ -53,12 +53,15 @@ public abstract class Bitcoiny implements ForeignBlockchain {
|
||||
/** Byte offset into raw block headers to block timestamp. */
|
||||
private static final int TIMESTAMP_OFFSET = 4 + 32 + 32;
|
||||
|
||||
protected Coin feePerKb;
|
||||
|
||||
// Constructors and instance
|
||||
|
||||
protected Bitcoiny(BitcoinyBlockchainProvider blockchainProvider, Context bitcoinjContext, String currencyCode) {
|
||||
protected Bitcoiny(BitcoinyBlockchainProvider blockchainProvider, Context bitcoinjContext, String currencyCode, Coin feePerKb) {
|
||||
this.blockchainProvider = blockchainProvider;
|
||||
this.bitcoinjContext = bitcoinjContext;
|
||||
this.currencyCode = currencyCode;
|
||||
this.feePerKb = feePerKb;
|
||||
|
||||
this.params = this.bitcoinjContext.getParams();
|
||||
}
|
||||
@ -167,7 +170,11 @@ public abstract class Bitcoiny implements ForeignBlockchain {
|
||||
|
||||
/** Returns fee per transaction KB. To be overridden for testnet/regtest. */
|
||||
public Coin getFeePerKb() {
|
||||
return this.bitcoinjContext.getFeePerKb();
|
||||
return this.feePerKb;
|
||||
}
|
||||
|
||||
public void setFeePerKb(Coin feePerKb) {
|
||||
this.feePerKb = feePerKb;
|
||||
}
|
||||
|
||||
/** Returns minimum order size in sats. To be overridden for coins that need to restrict order size. */
|
||||
@ -757,6 +764,10 @@ public abstract class Bitcoiny implements ForeignBlockchain {
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public abstract long getFeeCeiling();
|
||||
|
||||
public abstract void setFeeCeiling(long fee);
|
||||
|
||||
// UTXOProvider support
|
||||
|
||||
static class WalletAwareUTXOProvider implements UTXOProvider {
|
||||
|
@ -59,8 +59,7 @@ public class Digibyte extends Bitcoiny {
|
||||
|
||||
@Override
|
||||
public long getP2shFee(Long timestamp) {
|
||||
// TODO: This will need to be replaced with something better in the near future!
|
||||
return MAINNET_FEE;
|
||||
return this.getFeeCeiling();
|
||||
}
|
||||
},
|
||||
TEST3 {
|
||||
@ -110,6 +109,16 @@ public class Digibyte extends Bitcoiny {
|
||||
}
|
||||
};
|
||||
|
||||
private long feeCeiling = MAINNET_FEE;
|
||||
|
||||
public long getFeeCeiling() {
|
||||
return feeCeiling;
|
||||
}
|
||||
|
||||
public void setFeeCeiling(long feeCeiling) {
|
||||
this.feeCeiling = feeCeiling;
|
||||
}
|
||||
|
||||
public abstract NetworkParameters getParams();
|
||||
public abstract Collection<Server> getServers();
|
||||
public abstract String getGenesisHash();
|
||||
@ -123,7 +132,7 @@ public class Digibyte extends Bitcoiny {
|
||||
// Constructors and instance
|
||||
|
||||
private Digibyte(DigibyteNet digibyteNet, BitcoinyBlockchainProvider blockchain, Context bitcoinjContext, String currencyCode) {
|
||||
super(blockchain, bitcoinjContext, currencyCode);
|
||||
super(blockchain, bitcoinjContext, currencyCode, DEFAULT_FEE_PER_KB);
|
||||
this.digibyteNet = digibyteNet;
|
||||
|
||||
LOGGER.info(() -> String.format("Starting Digibyte support using %s", this.digibyteNet.name()));
|
||||
@ -152,11 +161,6 @@ public class Digibyte extends Bitcoiny {
|
||||
|
||||
// Actual useful methods for use by other classes
|
||||
|
||||
@Override
|
||||
public Coin getFeePerKb() {
|
||||
return DEFAULT_FEE_PER_KB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMinimumOrderAmount() {
|
||||
return MINIMUM_ORDER_AMOUNT;
|
||||
@ -173,4 +177,14 @@ public class Digibyte extends Bitcoiny {
|
||||
return this.digibyteNet.getP2shFee(timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFeeCeiling() {
|
||||
return this.digibyteNet.getFeeCeiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFeeCeiling(long fee) {
|
||||
|
||||
this.digibyteNet.setFeeCeiling( fee );
|
||||
}
|
||||
}
|
||||
|
@ -60,8 +60,7 @@ public class Dogecoin extends Bitcoiny {
|
||||
|
||||
@Override
|
||||
public long getP2shFee(Long timestamp) {
|
||||
// TODO: This will need to be replaced with something better in the near future!
|
||||
return MAINNET_FEE;
|
||||
return this.getFeeCeiling();
|
||||
}
|
||||
},
|
||||
TEST3 {
|
||||
@ -111,6 +110,16 @@ public class Dogecoin extends Bitcoiny {
|
||||
}
|
||||
};
|
||||
|
||||
private long feeCeiling = MAINNET_FEE;
|
||||
|
||||
public long getFeeCeiling() {
|
||||
return feeCeiling;
|
||||
}
|
||||
|
||||
public void setFeeCeiling(long feeCeiling) {
|
||||
this.feeCeiling = feeCeiling;
|
||||
}
|
||||
|
||||
public abstract NetworkParameters getParams();
|
||||
public abstract Collection<Server> getServers();
|
||||
public abstract String getGenesisHash();
|
||||
@ -124,7 +133,7 @@ public class Dogecoin extends Bitcoiny {
|
||||
// Constructors and instance
|
||||
|
||||
private Dogecoin(DogecoinNet dogecoinNet, BitcoinyBlockchainProvider blockchain, Context bitcoinjContext, String currencyCode) {
|
||||
super(blockchain, bitcoinjContext, currencyCode);
|
||||
super(blockchain, bitcoinjContext, currencyCode, DEFAULT_FEE_PER_KB);
|
||||
this.dogecoinNet = dogecoinNet;
|
||||
|
||||
LOGGER.info(() -> String.format("Starting Dogecoin support using %s", this.dogecoinNet.name()));
|
||||
@ -153,11 +162,6 @@ public class Dogecoin extends Bitcoiny {
|
||||
|
||||
// Actual useful methods for use by other classes
|
||||
|
||||
@Override
|
||||
public Coin getFeePerKb() {
|
||||
return DEFAULT_FEE_PER_KB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMinimumOrderAmount() {
|
||||
return MINIMUM_ORDER_AMOUNT;
|
||||
@ -174,4 +178,14 @@ public class Dogecoin extends Bitcoiny {
|
||||
return this.dogecoinNet.getP2shFee(timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFeeCeiling() {
|
||||
return this.dogecoinNet.getFeeCeiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFeeCeiling(long fee) {
|
||||
|
||||
this.dogecoinNet.setFeeCeiling( fee );
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +63,7 @@ public class Litecoin extends Bitcoiny {
|
||||
|
||||
@Override
|
||||
public long getP2shFee(Long timestamp) {
|
||||
// TODO: This will need to be replaced with something better in the near future!
|
||||
return MAINNET_FEE;
|
||||
return this.getFeeCeiling();
|
||||
}
|
||||
},
|
||||
TEST3 {
|
||||
@ -117,6 +116,16 @@ public class Litecoin extends Bitcoiny {
|
||||
}
|
||||
};
|
||||
|
||||
private long feeCeiling = MAINNET_FEE;
|
||||
|
||||
public long getFeeCeiling() {
|
||||
return feeCeiling;
|
||||
}
|
||||
|
||||
public void setFeeCeiling(long feeCeiling) {
|
||||
this.feeCeiling = feeCeiling;
|
||||
}
|
||||
|
||||
public abstract NetworkParameters getParams();
|
||||
public abstract Collection<ElectrumX.Server> getServers();
|
||||
public abstract String getGenesisHash();
|
||||
@ -130,7 +139,7 @@ public class Litecoin extends Bitcoiny {
|
||||
// Constructors and instance
|
||||
|
||||
private Litecoin(LitecoinNet litecoinNet, BitcoinyBlockchainProvider blockchain, Context bitcoinjContext, String currencyCode) {
|
||||
super(blockchain, bitcoinjContext, currencyCode);
|
||||
super(blockchain, bitcoinjContext, currencyCode, DEFAULT_FEE_PER_KB);
|
||||
this.litecoinNet = litecoinNet;
|
||||
|
||||
LOGGER.info(() -> String.format("Starting Litecoin support using %s", this.litecoinNet.name()));
|
||||
@ -159,12 +168,6 @@ public class Litecoin extends Bitcoiny {
|
||||
|
||||
// Actual useful methods for use by other classes
|
||||
|
||||
/** Default Litecoin fee is lower than Bitcoin: only 10sats/byte. */
|
||||
@Override
|
||||
public Coin getFeePerKb() {
|
||||
return DEFAULT_FEE_PER_KB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMinimumOrderAmount() {
|
||||
return MINIMUM_ORDER_AMOUNT;
|
||||
@ -181,4 +184,14 @@ public class Litecoin extends Bitcoiny {
|
||||
return this.litecoinNet.getP2shFee(timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFeeCeiling() {
|
||||
return this.litecoinNet.getFeeCeiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFeeCeiling(long fee) {
|
||||
|
||||
this.litecoinNet.setFeeCeiling( fee );
|
||||
}
|
||||
}
|
||||
|
@ -67,8 +67,7 @@ public class PirateChain extends Bitcoiny {
|
||||
|
||||
@Override
|
||||
public long getP2shFee(Long timestamp) {
|
||||
// TODO: This will need to be replaced with something better in the near future!
|
||||
return MAINNET_FEE;
|
||||
return this.getFeeCeiling();
|
||||
}
|
||||
},
|
||||
TEST3 {
|
||||
@ -118,6 +117,16 @@ public class PirateChain extends Bitcoiny {
|
||||
}
|
||||
};
|
||||
|
||||
private long feeCeiling = MAINNET_FEE;
|
||||
|
||||
public long getFeeCeiling() {
|
||||
return feeCeiling;
|
||||
}
|
||||
|
||||
public void setFeeCeiling(long feeCeiling) {
|
||||
this.feeCeiling = feeCeiling;
|
||||
}
|
||||
|
||||
public abstract NetworkParameters getParams();
|
||||
public abstract Collection<Server> getServers();
|
||||
public abstract String getGenesisHash();
|
||||
@ -131,7 +140,7 @@ public class PirateChain extends Bitcoiny {
|
||||
// Constructors and instance
|
||||
|
||||
private PirateChain(PirateChainNet pirateChainNet, BitcoinyBlockchainProvider blockchain, Context bitcoinjContext, String currencyCode) {
|
||||
super(blockchain, bitcoinjContext, currencyCode);
|
||||
super(blockchain, bitcoinjContext, currencyCode, DEFAULT_FEE_PER_KB);
|
||||
this.pirateChainNet = pirateChainNet;
|
||||
|
||||
LOGGER.info(() -> String.format("Starting Pirate Chain support using %s", this.pirateChainNet.name()));
|
||||
@ -160,12 +169,6 @@ public class PirateChain extends Bitcoiny {
|
||||
|
||||
// Actual useful methods for use by other classes
|
||||
|
||||
/** Default Litecoin fee is lower than Bitcoin: only 10sats/byte. */
|
||||
@Override
|
||||
public Coin getFeePerKb() {
|
||||
return DEFAULT_FEE_PER_KB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMinimumOrderAmount() {
|
||||
return MINIMUM_ORDER_AMOUNT;
|
||||
@ -182,6 +185,16 @@ public class PirateChain extends Bitcoiny {
|
||||
return this.pirateChainNet.getP2shFee(timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFeeCeiling() {
|
||||
return this.pirateChainNet.getFeeCeiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFeeCeiling(long fee) {
|
||||
|
||||
this.pirateChainNet.setFeeCeiling( fee );
|
||||
}
|
||||
/**
|
||||
* Returns confirmed balance, based on passed payment script.
|
||||
* <p>
|
||||
|
@ -61,8 +61,7 @@ public class Ravencoin extends Bitcoiny {
|
||||
|
||||
@Override
|
||||
public long getP2shFee(Long timestamp) {
|
||||
// TODO: This will need to be replaced with something better in the near future!
|
||||
return MAINNET_FEE;
|
||||
return this.getFeeCeiling();
|
||||
}
|
||||
},
|
||||
TEST3 {
|
||||
@ -112,6 +111,16 @@ public class Ravencoin extends Bitcoiny {
|
||||
}
|
||||
};
|
||||
|
||||
private long feeCeiling = MAINNET_FEE;
|
||||
|
||||
public long getFeeCeiling() {
|
||||
return feeCeiling;
|
||||
}
|
||||
|
||||
public void setFeeCeiling(long feeCeiling) {
|
||||
this.feeCeiling = feeCeiling;
|
||||
}
|
||||
|
||||
public abstract NetworkParameters getParams();
|
||||
public abstract Collection<Server> getServers();
|
||||
public abstract String getGenesisHash();
|
||||
@ -125,7 +134,7 @@ public class Ravencoin extends Bitcoiny {
|
||||
// Constructors and instance
|
||||
|
||||
private Ravencoin(RavencoinNet ravencoinNet, BitcoinyBlockchainProvider blockchain, Context bitcoinjContext, String currencyCode) {
|
||||
super(blockchain, bitcoinjContext, currencyCode);
|
||||
super(blockchain, bitcoinjContext, currencyCode, DEFAULT_FEE_PER_KB);
|
||||
this.ravencoinNet = ravencoinNet;
|
||||
|
||||
LOGGER.info(() -> String.format("Starting Ravencoin support using %s", this.ravencoinNet.name()));
|
||||
@ -154,11 +163,6 @@ public class Ravencoin extends Bitcoiny {
|
||||
|
||||
// Actual useful methods for use by other classes
|
||||
|
||||
@Override
|
||||
public Coin getFeePerKb() {
|
||||
return DEFAULT_FEE_PER_KB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMinimumOrderAmount() {
|
||||
return MINIMUM_ORDER_AMOUNT;
|
||||
@ -175,4 +179,14 @@ public class Ravencoin extends Bitcoiny {
|
||||
return this.ravencoinNet.getP2shFee(timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFeeCeiling() {
|
||||
return this.ravencoinNet.getFeeCeiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFeeCeiling(long fee) {
|
||||
|
||||
this.ravencoinNet.setFeeCeiling( fee );
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package org.qortal.data.crosschain;
|
||||
|
||||
import org.qortal.crosschain.BitcoinyTransaction;
|
||||
import org.qortal.crosschain.TransactionHash;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AtomicTransactionData {
|
||||
public final TransactionHash hash;
|
||||
public final Integer timestamp;
|
||||
public final List<BitcoinyTransaction.Input> inputs;
|
||||
public final Map<List<String>, Long> valueByAddress;
|
||||
public final long totalAmount;
|
||||
public final int size;
|
||||
|
||||
public AtomicTransactionData(
|
||||
TransactionHash hash,
|
||||
Integer timestamp,
|
||||
List<BitcoinyTransaction.Input> inputs,
|
||||
Map<List<String>, Long> valueByAddress,
|
||||
long totalAmount,
|
||||
int size) {
|
||||
|
||||
this.hash = hash;
|
||||
this.timestamp = timestamp;
|
||||
this.inputs = inputs;
|
||||
this.valueByAddress = valueByAddress;
|
||||
this.totalAmount = totalAmount;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
106
src/main/java/org/qortal/data/crosschain/TransactionSummary.java
Normal file
106
src/main/java/org/qortal/data/crosschain/TransactionSummary.java
Normal file
@ -0,0 +1,106 @@
|
||||
package org.qortal.data.crosschain;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class TransactionSummary {
|
||||
|
||||
private String atAddress;
|
||||
private String p2shValue;
|
||||
private String p2shAddress;
|
||||
private String lockingHash;
|
||||
private Integer lockingTimestamp;
|
||||
private long lockingTotalAmount;
|
||||
private long lockingFee;
|
||||
private int lockingSize;
|
||||
private String unlockingHash;
|
||||
private Integer unlockingTimestamp;
|
||||
private long unlockingTotalAmount;
|
||||
private long unlockingFee;
|
||||
private int unlockingSize;
|
||||
|
||||
public TransactionSummary(){}
|
||||
|
||||
public TransactionSummary(
|
||||
String atAddress,
|
||||
String p2shValue,
|
||||
String p2shAddress,
|
||||
String lockingHash,
|
||||
Integer lockingTimestamp,
|
||||
long lockingTotalAmount,
|
||||
long lockingFee,
|
||||
int lockingSize,
|
||||
String unlockingHash,
|
||||
Integer unlockingTimestamp,
|
||||
long unlockingTotalAmount,
|
||||
long unlockingFee,
|
||||
int unlockingSize) {
|
||||
|
||||
this.atAddress = atAddress;
|
||||
this.p2shValue = p2shValue;
|
||||
this.p2shAddress = p2shAddress;
|
||||
this.lockingHash = lockingHash;
|
||||
this.lockingTimestamp = lockingTimestamp;
|
||||
this.lockingTotalAmount = lockingTotalAmount;
|
||||
this.lockingFee = lockingFee;
|
||||
this.lockingSize = lockingSize;
|
||||
this.unlockingHash = unlockingHash;
|
||||
this.unlockingTimestamp = unlockingTimestamp;
|
||||
this.unlockingTotalAmount = unlockingTotalAmount;
|
||||
this.unlockingFee = unlockingFee;
|
||||
this.unlockingSize = unlockingSize;
|
||||
}
|
||||
|
||||
public String getAtAddress() {
|
||||
return atAddress;
|
||||
}
|
||||
|
||||
public String getP2shValue() {
|
||||
return p2shValue;
|
||||
}
|
||||
|
||||
public String getP2shAddress() {
|
||||
return p2shAddress;
|
||||
}
|
||||
|
||||
public String getLockingHash() {
|
||||
return lockingHash;
|
||||
}
|
||||
|
||||
public Integer getLockingTimestamp() {
|
||||
return lockingTimestamp;
|
||||
}
|
||||
|
||||
public long getLockingTotalAmount() {
|
||||
return lockingTotalAmount;
|
||||
}
|
||||
|
||||
public long getLockingFee() {
|
||||
return lockingFee;
|
||||
}
|
||||
|
||||
public int getLockingSize() {
|
||||
return lockingSize;
|
||||
}
|
||||
|
||||
public String getUnlockingHash() {
|
||||
return unlockingHash;
|
||||
}
|
||||
|
||||
public Integer getUnlockingTimestamp() {
|
||||
return unlockingTimestamp;
|
||||
}
|
||||
|
||||
public long getUnlockingTotalAmount() {
|
||||
return unlockingTotalAmount;
|
||||
}
|
||||
|
||||
public long getUnlockingFee() {
|
||||
return unlockingFee;
|
||||
}
|
||||
|
||||
public int getUnlockingSize() {
|
||||
return unlockingSize;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user