Merge branch 'develop'
This commit is contained in:
commit
80ff09d42f
28 changed files with 924 additions and 1657 deletions
24
.gitignore
vendored
24
.gitignore
vendored
|
@ -7,6 +7,9 @@
|
||||||
# Gradle
|
# Gradle
|
||||||
# ------
|
# ------
|
||||||
.gradle
|
.gradle
|
||||||
|
gradle
|
||||||
|
gradlew
|
||||||
|
gradlew.bat
|
||||||
/build
|
/build
|
||||||
/buildSrc/build
|
/buildSrc/build
|
||||||
/subprojects/*/build
|
/subprojects/*/build
|
||||||
|
@ -79,7 +82,24 @@ atlassian-ide-plugin.xml
|
||||||
# ----
|
# ----
|
||||||
/*.log
|
/*.log
|
||||||
|
|
||||||
src/main/java/com/luminiasoft/bitshares/mycelium/*
|
|
||||||
|
|
||||||
# Ignore bin backups
|
# Ignore bin backups
|
||||||
*.bin
|
*.bin
|
||||||
|
|
||||||
|
# [Maven]
|
||||||
|
# -------
|
||||||
|
target/
|
||||||
|
pom.xml.tag
|
||||||
|
pom.xml.releaseBackup
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
pom.xml.next
|
||||||
|
release.properties
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
|
|
||||||
|
# Build dir
|
||||||
|
graphenej/build
|
||||||
|
|
||||||
|
local.properties
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
|
@ -1,3 +0,0 @@
|
||||||
dependencies {
|
|
||||||
compile project(':graphenej')
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1,2 +0,0 @@
|
||||||
Manifest-Version: 1.0
|
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
package de.bitsharesmunich.graphenej;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
// Brain key from Nelson's app referencing the bilthon-83 account
|
|
||||||
public static final String BILTHON_83_BRAIN_KEY = System.getenv("BILTHON_83_BRAIN_KEY");
|
|
||||||
|
|
||||||
public static final String BILTHON_83_ORIGINAL_BRAIN_KEY = System.getenv("BILTHON_83_ORIGINAL_BRAIN_KEY");
|
|
||||||
|
|
||||||
public static final String BILTHON_1_BRAIN_KEY = System.getenv("BILTHON_1_BRAIN_KEY");
|
|
||||||
|
|
||||||
public static final String BILTHON_5_BRAIN_KEY = System.getenv("BILTHON_5_BRAIN_KEY");
|
|
||||||
|
|
||||||
public static final String BILTHON_7_BRAIN_KEY = System.getenv("BILTHON_7_BRAIN_KEY");
|
|
||||||
|
|
||||||
public static final String BIP39_KEY = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
|
|
||||||
|
|
||||||
public static final String WIF = "5KMzB2GqGhnh7ufhgddmz1eKPHS72uTLeL9hHjSvPb1UywWknF5";
|
|
||||||
|
|
||||||
public static final String BILTHON_83_PASSWORD = System.getenv("BILTHON_83_PASSWORD");
|
|
||||||
|
|
||||||
public static final String BILTHON_25_PASSWORD = System.getenv("BILTHON_25_PASSWORD");
|
|
||||||
|
|
||||||
public static final String BILTHON_11_BRAIN_KEY = System.getenv("BILTHON_11_BRAINKEY");
|
|
||||||
|
|
||||||
public static final String BILTHON_15_BRAIN_KEY = System.getenv("BILTHON_15_BRAINKEY");
|
|
||||||
|
|
||||||
public static final String BILTHON_16_BRAIN_KEY = System.getenv("BILTHON_16_BRAINKEY");
|
|
||||||
|
|
||||||
public static final String BILTHON_36_BRAIN_KEY = System.getenv("BILTHON_36_BRAINKEY");
|
|
||||||
|
|
||||||
public static final String GENERIC_PASSWORD = System.getenv("GENERIC_PASSWORD");
|
|
||||||
|
|
||||||
public static final String DISCLOSABLE_PASSWORD = System.getenv("DISCLOSABLE_PASSWORD");
|
|
||||||
|
|
||||||
// Static block information used for transaction serialization tests
|
|
||||||
public static int REF_BLOCK_NUM = 56204;
|
|
||||||
public static int REF_BLOCK_PREFIX = 1614747814;
|
|
||||||
public static int RELATIVE_EXPIRATION = 1478385607;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Test test = new Test();
|
|
||||||
|
|
||||||
// test.testTransactionSerialization();
|
|
||||||
// ECKey.ECDSASignature signature = test.testSigning();
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// test.testWebSocketTransfer();
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// test.testCustomSerializer();
|
|
||||||
// test.testUserAccountSerialization();
|
|
||||||
// test.testTransactionSerialization();
|
|
||||||
// test.testLoginSerialization();
|
|
||||||
// test.testNetworkBroadcastSerialization();
|
|
||||||
// test.testNetworkBroadcastDeserialization();
|
|
||||||
// test.testGetDynamicParams();
|
|
||||||
// test.testGetRequiredFeesSerialization();
|
|
||||||
// test.testRequiredFeesResponse();
|
|
||||||
// test.testTransactionBroadcastSequence();
|
|
||||||
// test.testAccountLookupDeserialization();
|
|
||||||
// test.testPrivateKeyManipulations();
|
|
||||||
// test.testPublicKeyManipulations();
|
|
||||||
// test.testGetAccountByName();
|
|
||||||
// test.testGetRequiredFees();
|
|
||||||
// test.testRandomNumberGeneration();
|
|
||||||
// test.testBrainKeyOperations(false);
|
|
||||||
// test.testBip39Opertion();
|
|
||||||
// test.testAccountNamebyAddress();
|
|
||||||
// test.testAccountNameById();
|
|
||||||
// test.testRelativeAccountHistory();
|
|
||||||
// test.testingInvoiceGeneration();
|
|
||||||
// test.testCompression();
|
|
||||||
// test.testAccountUpdateSerialization();
|
|
||||||
// test.testAccountUpdateOperationBroadcast();
|
|
||||||
// test.testCreateBinFile();
|
|
||||||
// test.testImportBinFile();
|
|
||||||
test.testExportBinFile();
|
|
||||||
// test.testLzmaCompression();
|
|
||||||
// test.testLzmaDecompression();
|
|
||||||
// test.testSimpleDecompression();
|
|
||||||
// test.testLookupAccounts();
|
|
||||||
// test.testLookupAccounts();
|
|
||||||
// test.testDecodeMemo();
|
|
||||||
// test.testGetRelativeAccountHistory();
|
|
||||||
// test.testLookupAssetSymbols();
|
|
||||||
// test.testListAssets();
|
|
||||||
// test.testGetObjects();
|
|
||||||
// test.testGetBlockHeader();
|
|
||||||
// test.testGetLimitOrders();
|
|
||||||
// test.testGetTradeHistory();
|
|
||||||
// test.testAssetSerialization();
|
|
||||||
// test.testGetMarketHistory();
|
|
||||||
// test.testGetAccountBalances();
|
|
||||||
// test.testGetAssetHoldersCount();
|
|
||||||
// test.testSubscription(null);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,8 +3,15 @@ allprojects {
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply plugin: "java"
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||||
|
}
|
||||||
|
}
|
33
gradle.properties
Normal file
33
gradle.properties
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Project-wide Gradle settings.
|
||||||
|
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||||
|
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||||
|
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
|
||||||
|
VERSION_NAME=0.4.1
|
||||||
|
VERSION_CODE=3
|
||||||
|
GROUP=com.github.kenCode-de
|
||||||
|
|
||||||
|
POM_DESCRIPTION=A Java library for mobile app Developers; Graphene/Bitshares blockchain.
|
||||||
|
POM_URL=https://github.com/kenCode-de/graphenej
|
||||||
|
POM_SCM_URL=https://github.com/kenCode-de/graphenej
|
||||||
|
POM_SCM_CONNECTION=scm:git@github.com:kenCode-de/graphenej.git
|
||||||
|
POM_SCM_DEV_CONNECTION=scm:git@github.com:kenCode-de/graphenej.git
|
||||||
|
POM_LICENCE_NAME=MIT License
|
||||||
|
POM_LICENCE_URL=https://github.com/kenCode-de/graphenej/blob/master/LICENSE
|
||||||
|
POM_LICENCE_DIST=repo
|
||||||
|
POM_DEVELOPER_ID=bilthon
|
||||||
|
POM_DEVELOPER_NAME=bilthon
|
|
@ -1,17 +1,9 @@
|
||||||
group 'de.bitsharesmunich'
|
group 'de.bitsharesmunich'
|
||||||
version '0.1-SNAPSHOT'
|
version '0.4.0-SNAPSHOT'
|
||||||
|
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
apply from: 'maven-push.gradle'
|
||||||
|
|
||||||
//apply plugin: 'java'
|
|
||||||
//
|
|
||||||
//model {
|
|
||||||
// components {
|
|
||||||
// main(JvmLibrarySpec)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//repositories {
|
|
||||||
// mavenCentral()
|
|
||||||
//}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||||
|
@ -20,3 +12,24 @@ dependencies {
|
||||||
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
|
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
|
||||||
compile group: "org.tukaani", name: "xz", version: "1.6"
|
compile group: "org.tukaani", name: "xz", version: "1.6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 24
|
||||||
|
buildToolsVersion "25.0.0"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 3
|
||||||
|
targetSdkVersion 24
|
||||||
|
versionCode 3
|
||||||
|
versionName "0.4.1"
|
||||||
|
|
||||||
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
graphenej/gradle.properties
Normal file
3
graphenej/gradle.properties
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
POM_NAME=Graphenej
|
||||||
|
POM_ARTIFACT_ID=graphenej
|
||||||
|
POM_PACKAGING=aar
|
112
graphenej/maven-push.gradle
Normal file
112
graphenej/maven-push.gradle
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Chris Banes
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
apply plugin: 'maven'
|
||||||
|
apply plugin: 'signing'
|
||||||
|
|
||||||
|
def isReleaseBuild() {
|
||||||
|
return VERSION_NAME.contains("SNAPSHOT") == false
|
||||||
|
}
|
||||||
|
|
||||||
|
def getReleaseRepositoryUrl() {
|
||||||
|
return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
|
||||||
|
: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
||||||
|
}
|
||||||
|
|
||||||
|
def getSnapshotRepositoryUrl() {
|
||||||
|
return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
|
||||||
|
: "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||||
|
}
|
||||||
|
|
||||||
|
def getRepositoryUsername() {
|
||||||
|
return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
|
||||||
|
}
|
||||||
|
|
||||||
|
def getRepositoryPassword() {
|
||||||
|
return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEvaluate { project ->
|
||||||
|
uploadArchives {
|
||||||
|
repositories {
|
||||||
|
mavenDeployer {
|
||||||
|
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||||
|
|
||||||
|
pom.groupId = GROUP
|
||||||
|
pom.artifactId = POM_ARTIFACT_ID
|
||||||
|
pom.version = VERSION_NAME
|
||||||
|
|
||||||
|
repository(url: getReleaseRepositoryUrl()) {
|
||||||
|
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
|
||||||
|
}
|
||||||
|
snapshotRepository(url: getSnapshotRepositoryUrl()) {
|
||||||
|
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
|
||||||
|
}
|
||||||
|
|
||||||
|
pom.project {
|
||||||
|
name POM_NAME
|
||||||
|
packaging POM_PACKAGING
|
||||||
|
description POM_DESCRIPTION
|
||||||
|
url POM_URL
|
||||||
|
|
||||||
|
scm {
|
||||||
|
url POM_SCM_URL
|
||||||
|
connection POM_SCM_CONNECTION
|
||||||
|
developerConnection POM_SCM_DEV_CONNECTION
|
||||||
|
}
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name POM_LICENCE_NAME
|
||||||
|
url POM_LICENCE_URL
|
||||||
|
distribution POM_LICENCE_DIST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id POM_DEVELOPER_ID
|
||||||
|
name POM_DEVELOPER_NAME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signing {
|
||||||
|
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
|
||||||
|
sign configurations.archives
|
||||||
|
}
|
||||||
|
|
||||||
|
//task androidJavadocs(type: Javadoc) {
|
||||||
|
//source = android.sourceSets.main.allJava
|
||||||
|
//}
|
||||||
|
|
||||||
|
//task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
|
||||||
|
//classifier = 'javadoc'
|
||||||
|
//from androidJavadocs.destinationDir
|
||||||
|
//}
|
||||||
|
|
||||||
|
task androidSourcesJar(type: Jar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
from android.sourceSets.main.java.sourceFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives androidSourcesJar
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
rootProject.name = 'graphenej'
|
|
||||||
include 'application'
|
|
||||||
|
|
9
graphenej/src/main/AndroidManifest.xml
Normal file
9
graphenej/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="de.bitsharesmunich.graphenej"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="0.4.0" >
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="1" />
|
||||||
|
<application/>
|
||||||
|
</manifest>
|
|
@ -1,67 +0,0 @@
|
||||||
package de.bitsharesmunich.graphenej;
|
|
||||||
|
|
||||||
import de.bitsharesmunich.graphenej.errors.MalformedTransactionException;
|
|
||||||
import de.bitsharesmunich.graphenej.operations.AccountUpdateOperation;
|
|
||||||
import org.bitcoinj.core.ECKey;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class used to build a transaction containing an account update operation.
|
|
||||||
*/
|
|
||||||
public class AccountUpdateTransactionBuilder extends TransactionBuilder {
|
|
||||||
private List<BaseOperation> operations;
|
|
||||||
private AssetAmount fee;
|
|
||||||
private UserAccount account;
|
|
||||||
private Authority owner;
|
|
||||||
private Authority active;
|
|
||||||
private AccountOptions new_options;
|
|
||||||
|
|
||||||
public AccountUpdateTransactionBuilder(ECKey privKey) {
|
|
||||||
super(privKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public AccountUpdateTransactionBuilder setAccont(UserAccount account){
|
|
||||||
this.account = account;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccountUpdateTransactionBuilder setOwner(Authority owner){
|
|
||||||
this.owner = owner;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccountUpdateTransactionBuilder setActive(Authority active){
|
|
||||||
this.active = active;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccountUpdateTransactionBuilder setOptions(AccountOptions options){
|
|
||||||
this.new_options = options;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccountUpdateTransactionBuilder setFee(AssetAmount fee){
|
|
||||||
this.fee = fee;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Transaction build() throws MalformedTransactionException {
|
|
||||||
if(account == null){
|
|
||||||
throw new MalformedTransactionException("Missing required account information");
|
|
||||||
}else{
|
|
||||||
operations = new ArrayList<>();
|
|
||||||
AccountUpdateOperation operation;
|
|
||||||
if(fee == null){
|
|
||||||
operation = new AccountUpdateOperation(account, owner, active, new_options);
|
|
||||||
}else{
|
|
||||||
operation = new AccountUpdateOperation(account, owner, active, new_options, fee);
|
|
||||||
}
|
|
||||||
operations.add(operation);
|
|
||||||
}
|
|
||||||
return new Transaction(privateKey, blockData, operations);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -129,6 +129,9 @@ public class AssetAmount implements ByteSerializable, JsonSerializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom deserializer used for this class
|
||||||
|
*/
|
||||||
public static class AssetAmountDeserializer implements JsonDeserializer<AssetAmount> {
|
public static class AssetAmountDeserializer implements JsonDeserializer<AssetAmount> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package de.bitsharesmunich.graphenej;
|
package de.bitsharesmunich.graphenej;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
|
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
|
||||||
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
|
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
|
||||||
|
|
||||||
|
@ -8,6 +10,9 @@ import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
|
||||||
*/
|
*/
|
||||||
public abstract class BaseOperation implements ByteSerializable, JsonSerializable {
|
public abstract class BaseOperation implements ByteSerializable, JsonSerializable {
|
||||||
|
|
||||||
|
public static final String KEY_FEE = "fee";
|
||||||
|
public static final String KEY_EXTENSIONS = "extensions";
|
||||||
|
|
||||||
protected OperationType type;
|
protected OperationType type;
|
||||||
protected Extensions extensions;
|
protected Extensions extensions;
|
||||||
|
|
||||||
|
@ -22,5 +27,9 @@ public abstract class BaseOperation implements ByteSerializable, JsonSerializabl
|
||||||
|
|
||||||
public abstract void setFee(AssetAmount assetAmount);
|
public abstract void setFee(AssetAmount assetAmount);
|
||||||
|
|
||||||
public abstract byte[] toBytes();
|
public JsonElement toJsonObject(){
|
||||||
|
JsonArray array = new JsonArray();
|
||||||
|
array.add(this.getId());
|
||||||
|
return array;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,131 @@
|
||||||
package de.bitsharesmunich.graphenej;
|
package de.bitsharesmunich.graphenej;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author henry
|
* @author henry
|
||||||
*/
|
*/
|
||||||
public class LimitOrder {
|
public class LimitOrder extends GrapheneObject implements ByteSerializable {
|
||||||
public String id;
|
|
||||||
public String expiration;
|
public static final String KEY_EXPIRATION = "expiration";
|
||||||
public UserAccount seller;
|
public static final String KEY_SELLER = "seller";
|
||||||
public long for_sale;
|
public static final String KEY_FOR_SALE = "for_sale";
|
||||||
public long deferred_fee;
|
public static final String KEY_DEFERRED_FEE = "deferred_fee";
|
||||||
public Price sell_price;
|
public static final String KEY_PRICE = "key_price";
|
||||||
|
|
||||||
|
private String expiration;
|
||||||
|
private UserAccount seller;
|
||||||
|
private long forSale;
|
||||||
|
private long deferredFee;
|
||||||
|
private Price sellPrice;
|
||||||
|
|
||||||
|
public LimitOrder(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExpiration() {
|
||||||
|
return expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiration(String expiration) {
|
||||||
|
this.expiration = expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAccount getSeller() {
|
||||||
|
return seller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeller(UserAccount seller) {
|
||||||
|
this.seller = seller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getForSale() {
|
||||||
|
return forSale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForSale(long forSale) {
|
||||||
|
this.forSale = forSale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDeferredFee() {
|
||||||
|
return deferredFee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeferredFee(long deferredFee) {
|
||||||
|
this.deferredFee = deferredFee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Price getSellPrice() {
|
||||||
|
return sellPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSellPrice(Price sellPrice) {
|
||||||
|
this.sellPrice = sellPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes() {
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
DataOutput out = new DataOutputStream(byteArrayOutputStream);
|
||||||
|
byte[] serialized = null;
|
||||||
|
try {
|
||||||
|
Varint.writeUnsignedVarLong(this.instance, out);
|
||||||
|
serialized = byteArrayOutputStream.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom deserializer for the LimitOrder class, used to deserialize a json-formatted string in
|
||||||
|
* the following format:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* "id": "1.7.2389233",
|
||||||
|
* "expiration": "2017-04-21T15:40:04",
|
||||||
|
* "seller": "1.2.114363",
|
||||||
|
* "forSale": "10564959415",
|
||||||
|
* "sell_price": {
|
||||||
|
* "base": {
|
||||||
|
* "amount": "10565237932",
|
||||||
|
* "asset_id": "1.3.0"
|
||||||
|
* },
|
||||||
|
* "quote": {
|
||||||
|
* "amount": 5803878,
|
||||||
|
* "asset_id": "1.3.121"
|
||||||
|
* }
|
||||||
|
* },
|
||||||
|
* "deferredFee": 0
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public static class LimitOrderDeserializer implements JsonDeserializer<LimitOrder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimitOrder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject object = json.getAsJsonObject();
|
||||||
|
String id = object.get(KEY_ID).getAsString();
|
||||||
|
String expiration = object.get(KEY_EXPIRATION).getAsString();
|
||||||
|
UserAccount seller = context.deserialize(object.get(KEY_SELLER), UserAccount.class);
|
||||||
|
String forSale = object.get(KEY_FOR_SALE).getAsString();
|
||||||
|
Price price = context.deserialize(object.get(KEY_PRICE), Price.class);
|
||||||
|
long deferredFee = object.get(KEY_DEFERRED_FEE).getAsLong();
|
||||||
|
|
||||||
|
LimitOrder limitOrder = new LimitOrder(id);
|
||||||
|
limitOrder.setExpiration(expiration);
|
||||||
|
limitOrder.setSeller(seller);
|
||||||
|
limitOrder.setForSale(Long.parseLong(forSale));
|
||||||
|
limitOrder.setSellPrice(price);
|
||||||
|
limitOrder.setDeferredFee(deferredFee);
|
||||||
|
return limitOrder;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package de.bitsharesmunich.graphenej;
|
|
||||||
|
|
||||||
import de.bitsharesmunich.graphenej.errors.MalformedTransactionException;
|
|
||||||
import org.bitcoinj.core.ECKey;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by nelson on 11/14/16.
|
|
||||||
*/
|
|
||||||
public abstract class TransactionBuilder {
|
|
||||||
protected ECKey privateKey;
|
|
||||||
protected BlockData blockData;
|
|
||||||
|
|
||||||
public TransactionBuilder(){}
|
|
||||||
|
|
||||||
public TransactionBuilder(ECKey privKey){
|
|
||||||
this.privateKey = privKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransactionBuilder setBlockData(BlockData blockData){
|
|
||||||
this.blockData = blockData;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Transaction build() throws MalformedTransactionException;
|
|
||||||
}
|
|
|
@ -59,6 +59,7 @@ public class GetLimitOrders extends WebSocketAdapter {
|
||||||
Type GetLimitOrdersResponse = new TypeToken<WitnessResponse<List<LimitOrder>>>() {}.getType();
|
Type GetLimitOrdersResponse = new TypeToken<WitnessResponse<List<LimitOrder>>>() {}.getType();
|
||||||
builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
|
builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
|
||||||
builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountSimpleDeserializer());
|
builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountSimpleDeserializer());
|
||||||
|
builder.registerTypeAdapter(LimitOrder.class, new LimitOrder.LimitOrderDeserializer());
|
||||||
WitnessResponse<List<LimitOrder>> witnessResponse = builder.create().fromJson(response, GetLimitOrdersResponse);
|
WitnessResponse<List<LimitOrder>> witnessResponse = builder.create().fromJson(response, GetLimitOrdersResponse);
|
||||||
if (witnessResponse.error != null) {
|
if (witnessResponse.error != null) {
|
||||||
this.mListener.onError(witnessResponse.error);
|
this.mListener.onError(witnessResponse.error);
|
||||||
|
|
|
@ -133,7 +133,7 @@ public class TransactionBroadcastSequence extends WebSocketAdapter {
|
||||||
websocket.sendText(call.toJsonString());
|
websocket.sendText(call.toJsonString());
|
||||||
}else if(baseResponse.id >= BROADCAST_TRANSACTION){
|
}else if(baseResponse.id >= BROADCAST_TRANSACTION){
|
||||||
Type WitnessResponseType = new TypeToken<WitnessResponse<String>>(){}.getType();
|
Type WitnessResponseType = new TypeToken<WitnessResponse<String>>(){}.getType();
|
||||||
WitnessResponse<WitnessResponse<String>> witnessResponse = gson.fromJson(response, WitnessResponseType);
|
WitnessResponse<String> witnessResponse = gson.fromJson(response, WitnessResponseType);
|
||||||
mListener.onSuccess(witnessResponse);
|
mListener.onSuccess(witnessResponse);
|
||||||
websocket.disconnect();
|
websocket.disconnect();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package de.bitsharesmunich.graphenej.operations;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import de.bitsharesmunich.graphenej.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by nelson on 3/21/17.
|
||||||
|
*/
|
||||||
|
public class LimitOrderCancelOperation extends BaseOperation {
|
||||||
|
|
||||||
|
// Constants used in the JSON representation
|
||||||
|
public static final String KEY_FEE_PAYING_ACCOUNT = "fee_paying_account";
|
||||||
|
public static final String KEY_ORDER_ID = "order";
|
||||||
|
|
||||||
|
|
||||||
|
public LimitOrderCancelOperation(LimitOrder order, UserAccount feePayingAccount) {
|
||||||
|
super(OperationType.LIMIT_ORDER_CANCEL_OPERATION);
|
||||||
|
this.order = order;
|
||||||
|
this.feePayingAccount = feePayingAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inner fields of a limit order cancel operation
|
||||||
|
private AssetAmount fee;
|
||||||
|
private UserAccount feePayingAccount;
|
||||||
|
private LimitOrder order;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJsonString() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement toJsonObject() {
|
||||||
|
JsonArray array = (JsonArray) super.toJsonObject();
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
if(fee != null)
|
||||||
|
jsonObject.add(KEY_FEE, fee.toJsonObject());
|
||||||
|
jsonObject.addProperty(KEY_FEE_PAYING_ACCOUNT, feePayingAccount.getObjectId());
|
||||||
|
jsonObject.addProperty(KEY_ORDER_ID, order.getObjectId());
|
||||||
|
jsonObject.add(KEY_EXTENSIONS, new JsonArray());
|
||||||
|
array.add(jsonObject);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFee(AssetAmount assetAmount) {
|
||||||
|
this.fee = assetAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes() {
|
||||||
|
byte[] feeBytes = this.fee.toBytes();
|
||||||
|
byte[] feePayingAccountBytes = this.feePayingAccount.toBytes();
|
||||||
|
byte[] orderIdBytes = this.order.toBytes();
|
||||||
|
byte[] extensions = this.extensions.toBytes();
|
||||||
|
return Bytes.concat(feeBytes, feePayingAccountBytes, orderIdBytes, extensions);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
package de.bitsharesmunich.graphenej.operations;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import de.bitsharesmunich.graphenej.*;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation used to denote the creation of a limit order on the blockchain.
|
||||||
|
*
|
||||||
|
* The blockchain will atempt to sell amount_to_sell.asset_id for as much min_to_receive.asset_id as possible.
|
||||||
|
* The fee will be paid by the seller's account. Market fees will apply as specified by the issuer of both the
|
||||||
|
* selling asset and the receiving asset as a percentage of the amount exchanged.
|
||||||
|
*
|
||||||
|
* If either the selling asset or the receiving asset is white list restricted, the order will only be created
|
||||||
|
* if the seller is on the white list of the restricted asset type.
|
||||||
|
*
|
||||||
|
* Market orders are matched in the order they are included in the block chain.
|
||||||
|
*/
|
||||||
|
public class LimitOrderCreateOperation extends BaseOperation {
|
||||||
|
// Number of bytes used for the expiration field.
|
||||||
|
private final int EXPIRATION_BYTE_LENGTH = 4;
|
||||||
|
|
||||||
|
// Constants used in the JSON representation
|
||||||
|
public static final String KEY_SELLER = "seller";
|
||||||
|
public static final String KEY_AMOUNT_TO_SELL = "amount_to_sell";
|
||||||
|
public static final String KEY_MIN_TO_RECEIVE = "min_to_receive";
|
||||||
|
public static final String KEY_EXPIRATION = "expiration";
|
||||||
|
public static final String KEY_FILL_OR_KILL = "fill_or_kill";
|
||||||
|
|
||||||
|
// Inner fields of a limit order
|
||||||
|
private AssetAmount fee;
|
||||||
|
private UserAccount seller;
|
||||||
|
private AssetAmount amountToSell;
|
||||||
|
private AssetAmount minToReceive;
|
||||||
|
private int expiration;
|
||||||
|
private boolean fillOrKill;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param seller: Id of the seller
|
||||||
|
* @param toSell: Id of the asset to sell
|
||||||
|
* @param minToReceive: The minimum amount of the asset to receive
|
||||||
|
* @param expiration: Expiration in seconds
|
||||||
|
* @param fillOrKill: If this flag is set the entire order must be filled or the operation is rejected.
|
||||||
|
*/
|
||||||
|
public LimitOrderCreateOperation(UserAccount seller, AssetAmount toSell, AssetAmount minToReceive, int expiration, boolean fillOrKill){
|
||||||
|
super(OperationType.LIMIT_ORDER_CREATE_OPERATION);
|
||||||
|
this.seller = seller;
|
||||||
|
this.amountToSell = toSell;
|
||||||
|
this.minToReceive = minToReceive;
|
||||||
|
this.expiration = expiration;
|
||||||
|
this.fillOrKill = fillOrKill;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJsonString() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement toJsonObject() {
|
||||||
|
JsonArray array = (JsonArray) super.toJsonObject();
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
if(fee != null)
|
||||||
|
jsonObject.add(KEY_FEE, fee.toJsonObject());
|
||||||
|
jsonObject.addProperty(KEY_SELLER, seller.toJsonString());
|
||||||
|
jsonObject.add(KEY_AMOUNT_TO_SELL, amountToSell.toJsonObject());
|
||||||
|
jsonObject.add(KEY_MIN_TO_RECEIVE, minToReceive.toJsonObject());
|
||||||
|
|
||||||
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
|
||||||
|
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
|
||||||
|
jsonObject.addProperty(KEY_EXPIRATION, simpleDateFormat.format(new Date(((long) expiration) * 1000)));
|
||||||
|
jsonObject.addProperty(KEY_FILL_OR_KILL, this.fillOrKill ? "true" : "false");
|
||||||
|
jsonObject.add(KEY_EXTENSIONS, new JsonArray());
|
||||||
|
array.add(jsonObject);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFee(AssetAmount assetAmount) {
|
||||||
|
this.fee = assetAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes() {
|
||||||
|
byte[] feeBytes = this.fee.toBytes();
|
||||||
|
byte[] sellerBytes = this.seller.toBytes();
|
||||||
|
byte[] amountBytes = this.amountToSell.toBytes();
|
||||||
|
byte[] minAmountBytes = this.minToReceive.toBytes();
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(EXPIRATION_BYTE_LENGTH);
|
||||||
|
buffer.putInt(this.expiration);
|
||||||
|
byte[] expirationBytes = Util.revertBytes(buffer.array());
|
||||||
|
|
||||||
|
byte[] fillOrKill = this.fillOrKill ? new byte[]{ 0x1 } : new byte[]{ 0x0 };
|
||||||
|
byte[] extensions = this.extensions.toBytes();
|
||||||
|
|
||||||
|
return Bytes.concat(feeBytes, sellerBytes, amountBytes, minAmountBytes, expirationBytes, fillOrKill, extensions);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,9 +14,7 @@ import java.lang.reflect.Type;
|
||||||
* Class used to encapsulate the TransferOperation operation related functionalities.
|
* Class used to encapsulate the TransferOperation operation related functionalities.
|
||||||
*/
|
*/
|
||||||
public class TransferOperation extends BaseOperation {
|
public class TransferOperation extends BaseOperation {
|
||||||
public static final String KEY_FEE = "fee";
|
|
||||||
public static final String KEY_AMOUNT = "amount";
|
public static final String KEY_AMOUNT = "amount";
|
||||||
public static final String KEY_EXTENSIONS = "extensions";
|
|
||||||
public static final String KEY_FROM = "from";
|
public static final String KEY_FROM = "from";
|
||||||
public static final String KEY_TO = "to";
|
public static final String KEY_TO = "to";
|
||||||
public static final String KEY_MEMO = "memo";
|
public static final String KEY_MEMO = "memo";
|
||||||
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
package de.bitsharesmunich.graphenej;
|
||||||
|
|
||||||
|
import com.google.common.primitives.UnsignedLong;
|
||||||
|
import com.neovisionaries.ws.client.WebSocket;
|
||||||
|
import com.neovisionaries.ws.client.WebSocketException;
|
||||||
|
import com.neovisionaries.ws.client.WebSocketFactory;
|
||||||
|
import de.bitsharesmunich.graphenej.api.GetLimitOrders;
|
||||||
|
import de.bitsharesmunich.graphenej.api.TransactionBroadcastSequence;
|
||||||
|
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
|
||||||
|
import de.bitsharesmunich.graphenej.models.BaseResponse;
|
||||||
|
import de.bitsharesmunich.graphenej.models.WitnessResponse;
|
||||||
|
import de.bitsharesmunich.graphenej.objects.Memo;
|
||||||
|
import de.bitsharesmunich.graphenej.operations.*;
|
||||||
|
import de.bitsharesmunich.graphenej.test.NaiveSSLContext;
|
||||||
|
import org.bitcoinj.core.ECKey;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by nelson on 3/6/17.
|
||||||
|
*/
|
||||||
|
public class TransactionTest {
|
||||||
|
private final String BILTHON_15_BRAIN_KEY = System.getenv("BILTHON_15_BRAINKEY");
|
||||||
|
private final String BILTHON_5_BRAIN_KEY = System.getenv("BILTHON_5_BRAINKEY");
|
||||||
|
private final String BILTHON_16_BRAIN_KEY = System.getenv("BILTHON_16_BRAINKEY");
|
||||||
|
|
||||||
|
private final String BLOCK_PAY_DE = System.getenv("BLOCKPAY_DE");
|
||||||
|
private final String BLOCK_PAY_FR = System.getenv("BLOCKPAY_FR");
|
||||||
|
|
||||||
|
// Transfer operation transaction
|
||||||
|
private final Asset CORE_ASSET = new Asset("1.3.0");
|
||||||
|
private final UserAccount bilthon_15 = new UserAccount("1.2.143563");
|
||||||
|
private final UserAccount bilthon_5 = new UserAccount("1.2.139313");
|
||||||
|
private final UserAccount bilthon_16 = new UserAccount("1.2.143569");
|
||||||
|
|
||||||
|
// Limit order create transaction
|
||||||
|
private final Asset BIT_USD = new Asset("1.3.121");
|
||||||
|
private UserAccount seller = bilthon_15;
|
||||||
|
private AssetAmount amountToSell = new AssetAmount(UnsignedLong.valueOf(100000), CORE_ASSET);
|
||||||
|
private AssetAmount minToReceive = new AssetAmount(UnsignedLong.valueOf(520), BIT_USD);
|
||||||
|
private long expiration;
|
||||||
|
|
||||||
|
// Lock object
|
||||||
|
private static final class Lock { }
|
||||||
|
private final Object lockObject = new Lock();
|
||||||
|
|
||||||
|
// Response
|
||||||
|
private BaseResponse baseResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic witness response listener that will just release the lock created in
|
||||||
|
* main thread.
|
||||||
|
*/
|
||||||
|
WitnessResponseListener listener = new WitnessResponseListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(WitnessResponse response) {
|
||||||
|
System.out.println("onSuccess");
|
||||||
|
baseResponse = response;
|
||||||
|
synchronized (this){
|
||||||
|
this.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(BaseResponse.Error error) {
|
||||||
|
System.out.println("onError. Msg: "+error.data.message);
|
||||||
|
synchronized (this){
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives the elements required for building a transaction, puts them together and broadcasts it.
|
||||||
|
* @param privateKey: The private key used to sign the transaction.
|
||||||
|
* @param operationList: The list of operations to include
|
||||||
|
* @param responseListener: The response listener.
|
||||||
|
* @param lockObject: Optional object to use as a lock
|
||||||
|
*/
|
||||||
|
private void broadcastTransaction(ECKey privateKey, List<BaseOperation> operationList, WitnessResponseListener responseListener, Object lockObject) {
|
||||||
|
try{
|
||||||
|
Transaction transaction = new Transaction(privateKey, null, operationList);
|
||||||
|
|
||||||
|
SSLContext context = null;
|
||||||
|
context = NaiveSSLContext.getInstance("TLS");
|
||||||
|
WebSocketFactory factory = new WebSocketFactory();
|
||||||
|
|
||||||
|
// Set the custom SSL context.
|
||||||
|
factory.setSSLContext(context);
|
||||||
|
|
||||||
|
WebSocket mWebSocket = factory.createSocket(BLOCK_PAY_DE);
|
||||||
|
|
||||||
|
mWebSocket.addListener(new TransactionBroadcastSequence(transaction, CORE_ASSET, responseListener));
|
||||||
|
mWebSocket.connect();
|
||||||
|
|
||||||
|
// If a lock object is specified, we use it
|
||||||
|
if(lockObject != null){
|
||||||
|
synchronized (lockObject){
|
||||||
|
lockObject.wait();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// Otherwise we just use this listener as the lock
|
||||||
|
synchronized (responseListener){
|
||||||
|
responseListener.wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.assertNotNull(baseResponse);
|
||||||
|
Assert.assertNull(baseResponse.error);
|
||||||
|
}catch(NoSuchAlgorithmException e){
|
||||||
|
System.out.println("NoSuchAlgoritmException. Msg: " + e.getMessage());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
System.out.println("InterruptedException. Msg: "+e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IOException. Msg: " + e.getMessage());
|
||||||
|
} catch (WebSocketException e) {
|
||||||
|
System.out.println("WebSocketException. Msg: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransferTransaction(){
|
||||||
|
ECKey sourcePrivateKey = new BrainKey(BILTHON_15_BRAIN_KEY, 0).getPrivateKey();
|
||||||
|
PublicKey to1 = new PublicKey(ECKey.fromPublicOnly(new BrainKey(BILTHON_5_BRAIN_KEY, 0).getPublicKey()));
|
||||||
|
PublicKey to2 = new PublicKey(ECKey.fromPublicOnly(new BrainKey(BILTHON_16_BRAIN_KEY, 0).getPublicKey()));
|
||||||
|
|
||||||
|
// Creating memo
|
||||||
|
long nonce = 1;
|
||||||
|
byte[] encryptedMessage = Memo.encryptMessage(sourcePrivateKey, to1, nonce, "another message");
|
||||||
|
Memo memo = new Memo(new Address(ECKey.fromPublicOnly(sourcePrivateKey.getPubKey())), new Address(to1.getKey()), nonce, encryptedMessage);
|
||||||
|
|
||||||
|
// Creating operation 1
|
||||||
|
TransferOperation transferOperation1 = new TransferOperationBuilder()
|
||||||
|
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), CORE_ASSET))
|
||||||
|
.setSource(bilthon_15)
|
||||||
|
.setDestination(bilthon_5) // bilthon-5
|
||||||
|
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), CORE_ASSET))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Creating operation 2
|
||||||
|
TransferOperation transferOperation2 = new TransferOperationBuilder()
|
||||||
|
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), CORE_ASSET))
|
||||||
|
.setSource(bilthon_15) // bilthon-15
|
||||||
|
.setDestination(bilthon_16) // bilthon-16
|
||||||
|
.setFee(new AssetAmount(UnsignedLong.valueOf(264174), CORE_ASSET))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
// Adding operations to the operation list
|
||||||
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
||||||
|
operationList.add(transferOperation1);
|
||||||
|
operationList.add(transferOperation2);
|
||||||
|
|
||||||
|
// Broadcasting transaction
|
||||||
|
broadcastTransaction(sourcePrivateKey, operationList, listener, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLimitOrderCreateTransaction(){
|
||||||
|
ECKey privateKey = new BrainKey(BILTHON_15_BRAIN_KEY, 0).getPrivateKey();
|
||||||
|
expiration = (System.currentTimeMillis() / 1000) + 60 * 60;
|
||||||
|
|
||||||
|
// Creating limit order creation operation
|
||||||
|
LimitOrderCreateOperation operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, (int) expiration, false);
|
||||||
|
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
|
||||||
|
|
||||||
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
||||||
|
operationList.add(operation);
|
||||||
|
|
||||||
|
// Broadcasting transaction
|
||||||
|
broadcastTransaction(privateKey, operationList, listener, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since tests should be independent of each other, in order to be able to test the cancellation of an
|
||||||
|
* existing order we must first proceed to create one. And after creating one, we must also retrieve
|
||||||
|
* its id in a separate call.
|
||||||
|
*
|
||||||
|
* All of this just makes this test a bit more complex, since we have 3 clearly defined tasks that require
|
||||||
|
* network communication
|
||||||
|
*
|
||||||
|
* 1- Create order
|
||||||
|
* 2- Retrieve order id
|
||||||
|
* 3- Send order cancellation tx
|
||||||
|
*
|
||||||
|
* Only the last one is what we actually want to test
|
||||||
|
*
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws WebSocketException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testLimitOrderCancelTransaction() throws NoSuchAlgorithmException, IOException, WebSocketException {
|
||||||
|
|
||||||
|
// We first must create a limit order for this test
|
||||||
|
ECKey privateKey = new BrainKey(BILTHON_15_BRAIN_KEY, 0).getPrivateKey();
|
||||||
|
expiration = (System.currentTimeMillis() / 1000) + 60 * 5;
|
||||||
|
|
||||||
|
// Creating limit order creation operation
|
||||||
|
LimitOrderCreateOperation operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, (int) expiration, false);
|
||||||
|
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
|
||||||
|
|
||||||
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
||||||
|
operationList.add(operation);
|
||||||
|
|
||||||
|
// Broadcasting transaction (Task 1)
|
||||||
|
broadcastTransaction(privateKey, operationList, new WitnessResponseListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(WitnessResponse response) {
|
||||||
|
|
||||||
|
System.out.println("onSuccess.0");
|
||||||
|
try{
|
||||||
|
// Setting up the assets
|
||||||
|
Asset base = amountToSell.getAsset();
|
||||||
|
Asset quote = minToReceive.getAsset();
|
||||||
|
|
||||||
|
SSLContext context = NaiveSSLContext.getInstance("TLS");
|
||||||
|
WebSocketFactory factory = new WebSocketFactory();
|
||||||
|
|
||||||
|
// Set the custom SSL context.
|
||||||
|
factory.setSSLContext(context);
|
||||||
|
WebSocket mWebSocket = factory.createSocket(BLOCK_PAY_DE);
|
||||||
|
|
||||||
|
// Requesting limit order to cancel (Task 2)
|
||||||
|
mWebSocket.addListener(new GetLimitOrders(base.getObjectId(), quote.getObjectId(), 100, new WitnessResponseListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(WitnessResponse response) {
|
||||||
|
System.out.println("onSuccess.1");
|
||||||
|
List<LimitOrder> orders = (List<LimitOrder>) response.result;
|
||||||
|
for(LimitOrder order : orders){
|
||||||
|
if(order.getSeller().getObjectId().equals(bilthon_15.getObjectId())){
|
||||||
|
|
||||||
|
// Instantiating a private key for bilthon-15
|
||||||
|
ECKey privateKey = new BrainKey(BILTHON_15_BRAIN_KEY, 0).getPrivateKey();
|
||||||
|
|
||||||
|
// Creating limit order cancellation operation
|
||||||
|
LimitOrderCancelOperation operation = new LimitOrderCancelOperation(order, bilthon_15);
|
||||||
|
ArrayList<BaseOperation> operationList = new ArrayList<>();
|
||||||
|
operationList.add(operation);
|
||||||
|
|
||||||
|
// Broadcasting order cancellation tx (Task 3)
|
||||||
|
broadcastTransaction(privateKey, operationList, new WitnessResponseListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(WitnessResponse response) {
|
||||||
|
System.out.println("onSuccess.2");
|
||||||
|
baseResponse = response;
|
||||||
|
synchronized (this){
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
synchronized (lockObject){
|
||||||
|
lockObject.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(BaseResponse.Error error) {
|
||||||
|
System.out.println("onError.2");
|
||||||
|
synchronized (this){
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
synchronized (lockObject){
|
||||||
|
lockObject.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(BaseResponse.Error error) {
|
||||||
|
System.out.println("onError.1");
|
||||||
|
System.out.println(error.data.message);
|
||||||
|
Assert.assertNull(error);
|
||||||
|
synchronized (lockObject){
|
||||||
|
lockObject.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
mWebSocket.connect();
|
||||||
|
|
||||||
|
}catch(NoSuchAlgorithmException e){
|
||||||
|
System.out.println("NoSuchAlgorithmException. Msg: "+e.getMessage());
|
||||||
|
} catch (WebSocketException e) {
|
||||||
|
System.out.println("WebSocketException. Msg: "+e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IOException. Msg: "+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(BaseResponse.Error error) {
|
||||||
|
System.out.println("OnError. Msg: "+error.message);
|
||||||
|
synchronized (this){
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, lockObject);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package de.bitsharesmunich.graphenej.operations;
|
||||||
|
|
||||||
|
import com.google.common.primitives.UnsignedLong;
|
||||||
|
import de.bitsharesmunich.graphenej.*;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by nelson on 3/21/17.
|
||||||
|
*/
|
||||||
|
public class LimitOrderCancelOperationTest {
|
||||||
|
private static final Asset CORE_ASSET = new Asset("1.3.0");
|
||||||
|
private UserAccount feePayingAccount;
|
||||||
|
private LimitOrder limitOrder;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup(){
|
||||||
|
feePayingAccount = new UserAccount("1.2.143563");
|
||||||
|
limitOrder = new LimitOrder("1.7.2360289");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toBytes() throws Exception {
|
||||||
|
LimitOrderCancelOperation operation = new LimitOrderCancelOperation(limitOrder, feePayingAccount);
|
||||||
|
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
|
||||||
|
byte[] serialized = operation.toBytes();
|
||||||
|
assertArrayEquals("Correct serialization", Util.hexToBytes("020000000000000000cbe108e187900100"), serialized);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package de.bitsharesmunich.graphenej.operations;
|
||||||
|
|
||||||
|
import com.google.common.primitives.UnsignedLong;
|
||||||
|
import de.bitsharesmunich.graphenej.Asset;
|
||||||
|
import de.bitsharesmunich.graphenej.AssetAmount;
|
||||||
|
import de.bitsharesmunich.graphenej.UserAccount;
|
||||||
|
import de.bitsharesmunich.graphenej.Util;
|
||||||
|
import org.hamcrest.core.IsEqual;
|
||||||
|
import org.hamcrest.core.IsNot;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by nelson on 3/6/17.
|
||||||
|
*/
|
||||||
|
public class LimitOrderCreateOperationTest {
|
||||||
|
private static final int AMOUNT_TO_SELL = 25000000;
|
||||||
|
private static final int MIN_TO_RECEIVE = 1;
|
||||||
|
private static final Asset CORE_ASSET = new Asset("1.3.0");
|
||||||
|
private static final Asset BIT_USD = new Asset("1.3.121");
|
||||||
|
private static final int DEFAULT_EXPIRATION = 1488831620; // 2017-03-06T20:20:20
|
||||||
|
|
||||||
|
private UserAccount seller;
|
||||||
|
private AssetAmount amountToSell;
|
||||||
|
private AssetAmount minToReceive;
|
||||||
|
private int expiration;
|
||||||
|
private boolean fillOrKill;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup(){
|
||||||
|
seller = new UserAccount("1.2.143563");
|
||||||
|
amountToSell = new AssetAmount(UnsignedLong.valueOf(AMOUNT_TO_SELL), CORE_ASSET);
|
||||||
|
minToReceive = new AssetAmount(UnsignedLong.valueOf(MIN_TO_RECEIVE), BIT_USD);
|
||||||
|
expiration = DEFAULT_EXPIRATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toBytes() throws Exception {
|
||||||
|
// Testing serialization of operation with fillOrKill parameter == true
|
||||||
|
LimitOrderCreateOperation operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, expiration, true);
|
||||||
|
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
|
||||||
|
byte[] serialized = operation.toBytes();
|
||||||
|
Assert.assertArrayEquals("Correct serialization", serialized, Util.hexToBytes("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580100"));
|
||||||
|
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580000")));
|
||||||
|
|
||||||
|
// Testing serialization of operation with fillOrKill parameter == false
|
||||||
|
operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, expiration, false);
|
||||||
|
operation.setFee(new AssetAmount(UnsignedLong.valueOf(2), CORE_ASSET));
|
||||||
|
serialized = operation.toBytes();
|
||||||
|
Assert.assertArrayEquals("Correct serialization", serialized, Util.hexToBytes("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580000"));
|
||||||
|
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580100")));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
rootProject.name = "Graphenej"
|
rootProject.name = "Graphenej"
|
||||||
|
|
||||||
include ":graphenej", ":app"
|
include ":graphenej"
|
||||||
|
|
Loading…
Reference in a new issue