limit_order_create_operation-bearing tx is successfully being created and accepted by the network
This commit is contained in:
parent
5ee4ef77f2
commit
a9a550491b
6 changed files with 212 additions and 20 deletions
|
@ -50,7 +50,7 @@ public class Main {
|
|||
// e.printStackTrace();
|
||||
// }
|
||||
// test.testCustomSerializer();
|
||||
test.testUserAccountSerialization();
|
||||
// test.testUserAccountSerialization();
|
||||
// test.testTransactionSerialization();
|
||||
// test.testLoginSerialization();
|
||||
// test.testNetworkBroadcastSerialization();
|
||||
|
@ -89,7 +89,7 @@ public class Main {
|
|||
// test.testGetObjects();
|
||||
// test.testGetBlockHeader();
|
||||
// test.testGetLimitOrders();
|
||||
// test.testGetTradeHistory();
|
||||
test.testGetTradeHistory();
|
||||
// test.testAssetSerialization();
|
||||
// test.testGetMarketHistory();
|
||||
// test.testGetAccountBalances();
|
||||
|
|
|
@ -276,12 +276,14 @@ public class Test {
|
|||
@Override
|
||||
public void onSuccess(WitnessResponse response) {
|
||||
System.out.println("onSuccess");
|
||||
System.out.println("Callback.Thread. name: "+Thread.currentThread().getName()+", id: "+Thread.currentThread().getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(BaseResponse.Error error) {
|
||||
System.out.println("onError");
|
||||
System.out.println(error.data.message);
|
||||
System.out.println("Callback.Thread. name: "+Thread.currentThread().getName()+", id: "+Thread.currentThread().getId());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -330,7 +332,7 @@ public class Test {
|
|||
|
||||
mWebSocket.addListener(new TransactionBroadcastSequence(transaction, new Asset("1.3.0"), listener));
|
||||
mWebSocket.connect();
|
||||
|
||||
System.out.println("Main.Thread. name: "+Thread.currentThread().getName()+", id: "+Thread.currentThread().getId());
|
||||
} catch (MalformedOperationException e) {
|
||||
System.out.println("MalformedTransactionException. Msg: " + e.getMessage());
|
||||
} catch (IOException e) {
|
||||
|
@ -1189,7 +1191,7 @@ public class Test {
|
|||
Calendar to = Calendar.getInstance();
|
||||
to.roll(Calendar.DAY_OF_MONTH, false);
|
||||
|
||||
mWebSocket.addListener(new GetTradeHistory("BTS", "EUR", "20161215T0130000", "20161212T233000",100, new WitnessResponseListener() {
|
||||
mWebSocket.addListener(new GetTradeHistory("BTS", "EUR", "20170309T0130000", "20161212T233000",100, new WitnessResponseListener() {
|
||||
@Override
|
||||
public void onSuccess(WitnessResponse response) {
|
||||
List<MarketTrade> orders = (List<MarketTrade>) response.result;
|
||||
|
|
|
@ -133,7 +133,7 @@ public class TransactionBroadcastSequence extends WebSocketAdapter {
|
|||
websocket.sendText(call.toJsonString());
|
||||
}else if(baseResponse.id >= BROADCAST_TRANSACTION){
|
||||
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);
|
||||
websocket.disconnect();
|
||||
}
|
||||
|
|
|
@ -9,9 +9,19 @@ 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.
|
||||
|
@ -27,15 +37,22 @@ public class LimitOrderCreateOperation extends BaseOperation {
|
|||
// Inner fields of a limit order
|
||||
private AssetAmount fee;
|
||||
private UserAccount seller;
|
||||
private AssetAmount toSell;
|
||||
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.toSell = toSell;
|
||||
this.amountToSell = toSell;
|
||||
this.minToReceive = minToReceive;
|
||||
this.expiration = expiration;
|
||||
this.fillOrKill = fillOrKill;
|
||||
|
@ -54,11 +71,14 @@ public class LimitOrderCreateOperation extends BaseOperation {
|
|||
if(fee != null)
|
||||
jsonObject.add(KEY_FEE, fee.toJsonObject());
|
||||
jsonObject.addProperty(KEY_SELLER, seller.toJsonString());
|
||||
jsonObject.add(KEY_AMOUNT_TO_SELL, toSell.toJsonObject());
|
||||
jsonObject.add(KEY_AMOUNT_TO_SELL, amountToSell.toJsonObject());
|
||||
jsonObject.add(KEY_MIN_TO_RECEIVE, minToReceive.toJsonObject());
|
||||
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
|
||||
jsonObject.addProperty(KEY_EXPIRATION, simpleDateFormat.format(new Date(expiration)));
|
||||
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;
|
||||
|
@ -73,7 +93,7 @@ public class LimitOrderCreateOperation extends BaseOperation {
|
|||
public byte[] toBytes() {
|
||||
byte[] feeBytes = this.fee.toBytes();
|
||||
byte[] sellerBytes = this.seller.toBytes();
|
||||
byte[] amountBytes = this.toSell.toBytes();
|
||||
byte[] amountBytes = this.amountToSell.toBytes();
|
||||
byte[] minAmountBytes = this.minToReceive.toBytes();
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(EXPIRATION_BYTE_LENGTH);
|
||||
|
@ -81,6 +101,8 @@ public class LimitOrderCreateOperation extends BaseOperation {
|
|||
byte[] expirationBytes = Util.revertBytes(buffer.array());
|
||||
|
||||
byte[] fillOrKill = this.fillOrKill ? new byte[]{ 0x1 } : new byte[]{ 0x0 };
|
||||
return Bytes.concat(feeBytes, sellerBytes, amountBytes, minAmountBytes, expirationBytes, fillOrKill);
|
||||
byte[] extensions = this.extensions.toBytes();
|
||||
|
||||
return Bytes.concat(feeBytes, sellerBytes, amountBytes, minAmountBytes, expirationBytes, fillOrKill, extensions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
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.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.LimitOrderCreateOperation;
|
||||
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperationTest;
|
||||
import de.bitsharesmunich.graphenej.operations.TransferOperation;
|
||||
import de.bitsharesmunich.graphenej.operations.TransferOperationBuilder;
|
||||
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;
|
||||
|
||||
WitnessResponseListener listener = new WitnessResponseListener() {
|
||||
@Override
|
||||
public void onSuccess(WitnessResponse response) {
|
||||
System.out.println("onSuccess");
|
||||
WitnessResponse<String> witnessResponse = response;
|
||||
Assert.assertNull(witnessResponse.result);
|
||||
synchronized (this){
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(BaseResponse.Error error) {
|
||||
System.out.println("onError");
|
||||
System.out.println(error.data.message);
|
||||
Assert.assertNull(error);
|
||||
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.
|
||||
*/
|
||||
private void broadcastTransaction(ECKey privateKey, List<BaseOperation> operationList, WitnessResponseListener responseListener) {
|
||||
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, listener));
|
||||
mWebSocket.connect();
|
||||
synchronized (responseListener){
|
||||
responseListener.wait();
|
||||
System.out.println("Wait released");
|
||||
}
|
||||
}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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
|
@ -17,11 +17,11 @@ import static org.junit.Assert.*;
|
|||
* Created by nelson on 3/6/17.
|
||||
*/
|
||||
public class LimitOrderCreateOperationTest {
|
||||
private final int AMOUNT_TO_SELL = 25000000;
|
||||
private final int MIN_TO_RECEIVE = 1;
|
||||
private final Asset CORE_ASSET = new Asset("1.3.0");
|
||||
private final Asset BIT_USD = new Asset("1.3.121");
|
||||
private final int DEFAULT_EXPIRATION = 1488831620; // 2017-03-06T20:20:20
|
||||
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;
|
||||
|
@ -43,14 +43,14 @@ public class LimitOrderCreateOperationTest {
|
|||
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("020000000000000000cbe10840787d01000000000001000000000000007984c4bd5801"));
|
||||
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd5800")));
|
||||
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("020000000000000000cbe10840787d01000000000001000000000000007984c4bd5800"));
|
||||
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd5801")));
|
||||
Assert.assertArrayEquals("Correct serialization", serialized, Util.hexToBytes("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580000"));
|
||||
Assert.assertThat("Incorrect serialization", serialized, IsNot.not(IsEqual.equalTo("020000000000000000cbe10840787d01000000000001000000000000007984c4bd580100")));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue