mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 12:15:51 +00:00
[FEATURE] improve memo support
- add MemoFormat property for memo - MemoFormat and MemoType must be valid ASCII - Memo content is converted on the serialization level - add parsed_* version of Memo content if the parser understand the format - support `text` and `json` MemoFormat [FIX] double serialization overriding Memo contents The copy made in from_json wasn't a deep copy
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
* Data type map.
|
* Data type map.
|
||||||
*
|
*
|
||||||
* Mapping of type ids to data types. The type id is specified by the high
|
* Mapping of type ids to data types. The type id is specified by the high
|
||||||
|
*
|
||||||
|
* For reference, see rippled's definition:
|
||||||
|
* https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol/SField.cpp
|
||||||
*/
|
*/
|
||||||
var TYPES_MAP = exports.types = [
|
var TYPES_MAP = exports.types = [
|
||||||
void(0),
|
void(0),
|
||||||
@@ -375,7 +378,7 @@ exports.ledger = {
|
|||||||
['Balance', REQUIRED],
|
['Balance', REQUIRED],
|
||||||
['LowLimit', REQUIRED],
|
['LowLimit', REQUIRED],
|
||||||
['HighLimit', REQUIRED]])
|
['HighLimit', REQUIRED]])
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.metadata = [
|
exports.metadata = [
|
||||||
[ 'TransactionIndex' , REQUIRED ],
|
[ 'TransactionIndex' , REQUIRED ],
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ function SerializedObject(buf) {
|
|||||||
|
|
||||||
SerializedObject.from_json = function(obj) {
|
SerializedObject.from_json = function(obj) {
|
||||||
// Create a copy of the object so we don't modify it
|
// Create a copy of the object so we don't modify it
|
||||||
var obj = extend({}, obj);
|
var obj = extend(true, {}, obj);
|
||||||
var so = new SerializedObject();
|
var so = new SerializedObject();
|
||||||
var typedef;
|
var typedef;
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ var Currency = amount.Currency;
|
|||||||
// Shortcuts
|
// Shortcuts
|
||||||
var hex = sjcl.codec.hex;
|
var hex = sjcl.codec.hex;
|
||||||
var bytes = sjcl.codec.bytes;
|
var bytes = sjcl.codec.bytes;
|
||||||
|
var utf8 = sjcl.codec.utf8String;
|
||||||
|
|
||||||
var BigInteger = utils.jsbn.BigInteger;
|
var BigInteger = utils.jsbn.BigInteger;
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ function isBigInteger(val) {
|
|||||||
return val instanceof BigInteger;
|
return val instanceof BigInteger;
|
||||||
};
|
};
|
||||||
|
|
||||||
function serialize_hex(so, hexData, noLength) {
|
function serializeHex(so, hexData, noLength) {
|
||||||
var byteData = bytes.fromBits(hex.toBits(hexData));
|
var byteData = bytes.fromBits(hex.toBits(hexData));
|
||||||
if (!noLength) {
|
if (!noLength) {
|
||||||
SerializedType.serialize_varint(so, byteData.length);
|
SerializedType.serialize_varint(so, byteData.length);
|
||||||
@@ -63,10 +64,18 @@ function serialize_hex(so, hexData, noLength) {
|
|||||||
/**
|
/**
|
||||||
* parses bytes as hex
|
* parses bytes as hex
|
||||||
*/
|
*/
|
||||||
function convert_bytes_to_hex (byte_array) {
|
function convertByteArrayToHex (byte_array) {
|
||||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array)).toUpperCase();
|
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array)).toUpperCase();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function convertStringToHex(string) {
|
||||||
|
return hex.fromBits(utf8.toBits(string)).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertHexToString(hexString) {
|
||||||
|
return utf8.fromBits(hex.toBits(hexString));
|
||||||
|
}
|
||||||
|
|
||||||
SerializedType.serialize_varint = function (so, val) {
|
SerializedType.serialize_varint = function (so, val) {
|
||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
throw new Error('Variable integers are unsigned.');
|
throw new Error('Variable integers are unsigned.');
|
||||||
@@ -115,7 +124,7 @@ SerializedType.prototype.parse_varint = function (so) {
|
|||||||
*
|
*
|
||||||
* The result is appended to the serialized object ('so').
|
* The result is appended to the serialized object ('so').
|
||||||
*/
|
*/
|
||||||
function append_byte_array(so, val, bytes) {
|
function convertIntegerToByteArray(val, bytes) {
|
||||||
if (!isNumber(val)) {
|
if (!isNumber(val)) {
|
||||||
throw new Error('Value is not a number', bytes);
|
throw new Error('Value is not a number', bytes);
|
||||||
}
|
}
|
||||||
@@ -130,7 +139,7 @@ function append_byte_array(so, val, bytes) {
|
|||||||
newBytes.unshift(val >>> (i * 8) & 0xff);
|
newBytes.unshift(val >>> (i * 8) & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
so.append(newBytes);
|
return newBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert a certain number of bytes from the serialized object ('so') into an integer.
|
// Convert a certain number of bytes from the serialized object ('so') into an integer.
|
||||||
@@ -152,7 +161,7 @@ function readAndSum(so, bytes) {
|
|||||||
|
|
||||||
var STInt8 = exports.Int8 = new SerializedType({
|
var STInt8 = exports.Int8 = new SerializedType({
|
||||||
serialize: function (so, val) {
|
serialize: function (so, val) {
|
||||||
append_byte_array(so, val, 1);
|
so.append(convertIntegerToByteArray(val, 1));
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return readAndSum(so, 1);
|
return readAndSum(so, 1);
|
||||||
@@ -163,7 +172,7 @@ STInt8.id = 16;
|
|||||||
|
|
||||||
var STInt16 = exports.Int16 = new SerializedType({
|
var STInt16 = exports.Int16 = new SerializedType({
|
||||||
serialize: function (so, val) {
|
serialize: function (so, val) {
|
||||||
append_byte_array(so, val, 2);
|
so.append(convertIntegerToByteArray(val, 2));
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return readAndSum(so, 2);
|
return readAndSum(so, 2);
|
||||||
@@ -174,7 +183,7 @@ STInt16.id = 1;
|
|||||||
|
|
||||||
var STInt32 = exports.Int32 = new SerializedType({
|
var STInt32 = exports.Int32 = new SerializedType({
|
||||||
serialize: function (so, val) {
|
serialize: function (so, val) {
|
||||||
append_byte_array(so, val, 4);
|
so.append(convertIntegerToByteArray(val, 4));
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return readAndSum(so, 4);
|
return readAndSum(so, 4);
|
||||||
@@ -217,7 +226,7 @@ var STInt64 = exports.Int64 = new SerializedType({
|
|||||||
hex = '0' + hex;
|
hex = '0' + hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize_hex(so, hex, true); //noLength = true
|
serializeHex(so, hex, true); //noLength = true
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
var bytes = so.read(8);
|
var bytes = so.read(8);
|
||||||
@@ -237,7 +246,7 @@ var STHash128 = exports.Hash128 = new SerializedType({
|
|||||||
if (!hash.is_valid()) {
|
if (!hash.is_valid()) {
|
||||||
throw new Error('Invalid Hash128');
|
throw new Error('Invalid Hash128');
|
||||||
}
|
}
|
||||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
serializeHex(so, hash.to_hex(), true); //noLength = true
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return UInt128.from_bytes(so.read(16));
|
return UInt128.from_bytes(so.read(16));
|
||||||
@@ -252,7 +261,7 @@ var STHash256 = exports.Hash256 = new SerializedType({
|
|||||||
if (!hash.is_valid()) {
|
if (!hash.is_valid()) {
|
||||||
throw new Error('Invalid Hash256');
|
throw new Error('Invalid Hash256');
|
||||||
}
|
}
|
||||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
serializeHex(so, hash.to_hex(), true); //noLength = true
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return UInt256.from_bytes(so.read(32));
|
return UInt256.from_bytes(so.read(32));
|
||||||
@@ -267,7 +276,7 @@ var STHash160 = exports.Hash160 = new SerializedType({
|
|||||||
if (!hash.is_valid()) {
|
if (!hash.is_valid()) {
|
||||||
throw new Error('Invalid Hash160');
|
throw new Error('Invalid Hash160');
|
||||||
}
|
}
|
||||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
serializeHex(so, hash.to_hex(), true); //noLength = true
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return UInt160.from_bytes(so.read(20));
|
return UInt160.from_bytes(so.read(20));
|
||||||
@@ -294,7 +303,7 @@ var STCurrency = new SerializedType({
|
|||||||
// UInt160 value and consider it valid. But it doesn't, so for the
|
// UInt160 value and consider it valid. But it doesn't, so for the
|
||||||
// deserialization to be usable, we need to allow invalid results for now.
|
// deserialization to be usable, we need to allow invalid results for now.
|
||||||
//if (!currency.is_valid()) {
|
//if (!currency.is_valid()) {
|
||||||
// throw new Error('Invalid currency: '+convert_bytes_to_hex(bytes));
|
// throw new Error('Invalid currency: '+convertByteArrayToHex(bytes));
|
||||||
//}
|
//}
|
||||||
return currency;
|
return currency;
|
||||||
}
|
}
|
||||||
@@ -409,15 +418,16 @@ STAmount.id = 6;
|
|||||||
|
|
||||||
var STVL = exports.VariableLength = exports.VL = new SerializedType({
|
var STVL = exports.VariableLength = exports.VL = new SerializedType({
|
||||||
serialize: function (so, val) {
|
serialize: function (so, val) {
|
||||||
|
|
||||||
if (typeof val === 'string') {
|
if (typeof val === 'string') {
|
||||||
serialize_hex(so, val);
|
serializeHex(so, val);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown datatype.');
|
throw new Error('Unknown datatype.');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
var len = this.parse_varint(so);
|
var len = this.parse_varint(so);
|
||||||
return convert_bytes_to_hex(so.read(len));
|
return convertByteArrayToHex(so.read(len));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -429,7 +439,7 @@ var STAccount = exports.Account = new SerializedType({
|
|||||||
if (!account.is_valid()) {
|
if (!account.is_valid()) {
|
||||||
throw new Error('Invalid account!');
|
throw new Error('Invalid account!');
|
||||||
}
|
}
|
||||||
serialize_hex(so, account.to_hex());
|
serializeHex(so, account.to_hex());
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
var len = this.parse_varint(so);
|
var len = this.parse_varint(so);
|
||||||
@@ -441,7 +451,6 @@ var STAccount = exports.Account = new SerializedType({
|
|||||||
var result = UInt160.from_bytes(so.read(len));
|
var result = UInt160.from_bytes(so.read(len));
|
||||||
result.set_version(Base.VER_ACCOUNT_ID);
|
result.set_version(Base.VER_ACCOUNT_ID);
|
||||||
|
|
||||||
//console.log('PARSED 160:', result.to_json());
|
|
||||||
if (false && !result.is_valid()) {
|
if (false && !result.is_valid()) {
|
||||||
throw new Error('Invalid Account');
|
throw new Error('Invalid Account');
|
||||||
}
|
}
|
||||||
@@ -593,6 +602,105 @@ var STVector256 = exports.Vector256 = new SerializedType({
|
|||||||
|
|
||||||
STVector256.id = 19;
|
STVector256.id = 19;
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
var STMemo = exports.STMemo = new SerializedType({
|
||||||
|
serialize: function(so, val, no_marker) {
|
||||||
|
|
||||||
|
var keys = [];
|
||||||
|
|
||||||
|
Object.keys(val).forEach(function (key) {
|
||||||
|
// Ignore lowercase field names - they're non-serializable fields by
|
||||||
|
// convention.
|
||||||
|
if (key[0] === key[0].toLowerCase()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof binformat.fieldsInverseMap[key] === 'undefined') {
|
||||||
|
throw new Error('JSON contains unknown field: "' + key + '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.push(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort fields
|
||||||
|
keys = sort_fields(keys);
|
||||||
|
|
||||||
|
// store that we're dealing with json
|
||||||
|
var isJson = val.MemoFormat === 'json';
|
||||||
|
|
||||||
|
for (var i=0; i<keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = val[key];
|
||||||
|
switch (key) {
|
||||||
|
|
||||||
|
// MemoType and MemoFormat are always ASCII strings
|
||||||
|
case 'MemoType':
|
||||||
|
case 'MemoFormat':
|
||||||
|
value = convertStringToHex(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// MemoData can be a JSON object, otherwise it's a string
|
||||||
|
case 'MemoData':
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
if (isJson) {
|
||||||
|
try {
|
||||||
|
value = convertStringToHex(JSON.stringify(value));
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('MemoFormat json with invalid JSON in MemoData field');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('MemoData can only be a JSON object with a valid json MemoFormat');
|
||||||
|
}
|
||||||
|
} else if (isString(value)) {
|
||||||
|
value = convertStringToHex(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(so, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!no_marker) {
|
||||||
|
//Object ending marker
|
||||||
|
STInt8.serialize(so, 0xe1);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
parse: function(so) {
|
||||||
|
var output = {};
|
||||||
|
while (so.peek(1)[0] !== 0xe1) {
|
||||||
|
var keyval = parse(so);
|
||||||
|
output[keyval[0]] = keyval[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output['MemoType'] !== void(0)) {
|
||||||
|
output['parsed_memo_type'] = convertHexToString(output['MemoType']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output['MemoFormat'] !== void(0)) {
|
||||||
|
output['parsed_memo_format'] = convertHexToString(output['MemoFormat']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output['MemoData'] !== void(0)) {
|
||||||
|
|
||||||
|
// see if we can parse JSON
|
||||||
|
if (output['parsed_memo_format'] === 'json') {
|
||||||
|
try {
|
||||||
|
output['parsed_memo_data'] = JSON.parse(convertHexToString(output['MemoData']));
|
||||||
|
} catch(e) {
|
||||||
|
// fail, which is fine, we just won't add the memo_data field
|
||||||
|
}
|
||||||
|
} else if(output['parsed_memo_format'] === 'text') {
|
||||||
|
output['parsed_memo_data'] = convertHexToString(output['MemoData']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
so.read(1);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
exports.serialize = exports.serialize_whatever = serialize;
|
exports.serialize = exports.serialize_whatever = serialize;
|
||||||
|
|
||||||
function serialize(so, field_name, value) {
|
function serialize(so, field_name, value) {
|
||||||
@@ -622,9 +730,15 @@ function serialize(so, field_name, value) {
|
|||||||
STInt8.serialize(so, field_bits);
|
STInt8.serialize(so, field_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the serializer class (ST...) for a field based on the type bits.
|
// Get the serializer class (ST...)
|
||||||
var serialized_object_type = exports[binformat.types[type_bits]];
|
var serialized_object_type;
|
||||||
//do something with val[keys] and val[keys[i]];
|
if (field_name === 'Memo' && typeof value === 'object') {
|
||||||
|
// for Memo we override the default behavior with our STMemo serializer
|
||||||
|
serialized_object_type = exports.STMemo;
|
||||||
|
} else {
|
||||||
|
// for a field based on the type bits.
|
||||||
|
serialized_object_type = exports[binformat.types[type_bits]];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serialized_object_type.serialize(so, value);
|
serialized_object_type.serialize(so, value);
|
||||||
@@ -645,18 +759,21 @@ function parse(so) {
|
|||||||
type_bits = so.read(1)[0];
|
type_bits = so.read(1)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the parser class (ST...) for a field based on the type bits.
|
|
||||||
var type = exports[binformat.types[type_bits]];
|
|
||||||
|
|
||||||
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
|
|
||||||
|
|
||||||
var field_bits = tag_byte & 0x0f;
|
var field_bits = tag_byte & 0x0f;
|
||||||
var field_name = (field_bits === 0)
|
var field_name = (field_bits === 0)
|
||||||
? field_name = binformat.fields[type_bits][so.read(1)[0]]
|
? field_name = binformat.fields[type_bits][so.read(1)[0]]
|
||||||
: field_name = binformat.fields[type_bits][field_bits];
|
: field_name = binformat.fields[type_bits][field_bits];
|
||||||
|
|
||||||
assert(field_name, 'Unknown field - header byte is 0x' + tag_byte.toString(16));
|
assert(field_name, 'Unknown field - header byte is 0x' + tag_byte.toString(16));
|
||||||
|
|
||||||
|
// Get the parser class (ST...) for a field based on the type bits.
|
||||||
|
var type = (field_name === 'Memo')
|
||||||
|
? exports.STMemo
|
||||||
|
: exports[binformat.types[type_bits]];
|
||||||
|
|
||||||
|
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
|
||||||
|
|
||||||
return [ field_name, type.parse(so) ]; //key, value
|
return [ field_name, type.parse(so) ]; //key, value
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -678,18 +795,20 @@ function sort_fields(keys) {
|
|||||||
|
|
||||||
var STObject = exports.Object = new SerializedType({
|
var STObject = exports.Object = new SerializedType({
|
||||||
serialize: function (so, val, no_marker) {
|
serialize: function (so, val, no_marker) {
|
||||||
var keys = Object.keys(val);
|
var keys = [];
|
||||||
|
|
||||||
// Ignore lowercase field names - they're non-serializable fields by
|
Object.keys(val).forEach(function (key) {
|
||||||
// convention.
|
// Ignore lowercase field names - they're non-serializable fields by
|
||||||
keys = keys.filter(function (key) {
|
// convention.
|
||||||
return key[0] !== key[0].toLowerCase();
|
if (key[0] === key[0].toLowerCase()) {
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
keys.forEach(function (key) {
|
|
||||||
if (typeof binformat.fieldsInverseMap[key] === 'undefined') {
|
if (typeof binformat.fieldsInverseMap[key] === 'undefined') {
|
||||||
throw new Error('JSON contains unknown field: "' + key + '"');
|
throw new Error('JSON contains unknown field: "' + key + '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keys.push(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort fields
|
// Sort fields
|
||||||
|
|||||||
@@ -801,47 +801,56 @@ Transaction.prototype.setFlags = function(flags) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a Memo to transaction
|
* Add a Memo to transaction.
|
||||||
*
|
*
|
||||||
* @param {String} memoType
|
* @param {String} memoType
|
||||||
* - describes what the data represents, needs to be valid ASCII
|
* - describes what the data represents, needs to be valid ASCII
|
||||||
|
* * @param {String} memoFormat
|
||||||
|
* - describes what format the data is in, MIME type, needs to be valid ASCII
|
||||||
* @param {String} memoData
|
* @param {String} memoData
|
||||||
* - data for the memo, can be any JS object. Any object other than string will
|
* - data for the memo, can be any JS object. Any object other than string will
|
||||||
* be stringified (JSON) for transport
|
* be stringified (JSON) for transport
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Transaction.prototype.addMemo = function(memoType, memoData) {
|
Transaction.prototype.addMemo = function(memoType, memoFormat, memoData) {
|
||||||
|
|
||||||
if (typeof memoType === 'object') {
|
if (typeof memoType === 'object') {
|
||||||
var opts = memoType;
|
var opts = memoType;
|
||||||
memoType = opts.memoType;
|
memoType = opts.memoType;
|
||||||
|
memoFormat = opts.memoFormat;
|
||||||
memoData = opts.memoData;
|
memoData = opts.memoData;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!/(undefined|string)/.test(typeof memoType)) {
|
if (!/(undefined|string)/.test(typeof memoType)) {
|
||||||
throw new Error('MemoType must be a string');
|
throw new Error('MemoType must be a string');
|
||||||
|
} else if (!Transaction.ASCII_REGEX.test(memoType)) {
|
||||||
|
throw new Error('MemoType must be valid ASCII');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!/(undefined|string)/.test(typeof memoData)) {
|
if (!/(undefined|string)/.test(typeof memoFormat)) {
|
||||||
throw new Error('MemoData must be a string');
|
throw new Error('MemoFormat must be a string');
|
||||||
|
} else if (!Transaction.ASCII_REGEX.test(memoFormat)) {
|
||||||
|
throw new Error('MemoFormat must be valid ASCII');
|
||||||
}
|
}
|
||||||
|
|
||||||
function toHex(str) {
|
var memo = {};
|
||||||
return sjcl.codec.hex.fromBits(sjcl.codec.utf8String.toBits(str));
|
|
||||||
};
|
|
||||||
|
|
||||||
var memo = { };
|
|
||||||
|
|
||||||
if (memoType) {
|
if (memoType) {
|
||||||
if (Transaction.MEMO_TYPES[memoType]) {
|
if (Transaction.MEMO_TYPES[memoType]) {
|
||||||
//XXX Maybe in the future we want a schema validator for memo types
|
//XXX Maybe in the future we want a schema validator for
|
||||||
|
//memo types
|
||||||
memo.MemoType = Transaction.MEMO_TYPES[memoType];
|
memo.MemoType = Transaction.MEMO_TYPES[memoType];
|
||||||
} else {
|
} else {
|
||||||
memo.MemoType = toHex(memoType);
|
memo.MemoType = memoType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (memoFormat) {
|
||||||
|
memo.MemoFormat = memoFormat;
|
||||||
|
}
|
||||||
|
|
||||||
if (memoData) {
|
if (memoData) {
|
||||||
memo.MemoData = toHex(memoData);
|
memo.MemoData = memoData;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tx_json.Memos = (this.tx_json.Memos || []).concat({ Memo: memo });
|
this.tx_json.Memos = (this.tx_json.Memos || []).concat({ Memo: memo });
|
||||||
|
|||||||
@@ -1,8 +1,23 @@
|
|||||||
var utils = require('./testutils');
|
var utils = require('./testutils');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var SerializedObject = utils.load_module('serializedobject').SerializedObject;
|
var SerializedObject = utils.load_module('serializedobject').SerializedObject;
|
||||||
|
var sjcl = require('./../src/js/ripple/utils').sjcl;
|
||||||
|
|
||||||
|
// Shortcuts
|
||||||
|
var hex = sjcl.codec.hex;
|
||||||
|
var bytes = sjcl.codec.bytes;
|
||||||
|
var utf8 = sjcl.codec.utf8String;
|
||||||
|
|
||||||
describe('Serialized object', function() {
|
describe('Serialized object', function() {
|
||||||
|
|
||||||
|
function convertStringToHex(string) {
|
||||||
|
return hex.fromBits(utf8.toBits(string)).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertHexToString(hexString) {
|
||||||
|
return utf8.fromBits(hex.toBits(hexString));
|
||||||
|
}
|
||||||
|
|
||||||
describe('#from_json(v).to_json() == v', function(){
|
describe('#from_json(v).to_json() == v', function(){
|
||||||
it('outputs same as passed to from_json', function() {
|
it('outputs same as passed to from_json', function() {
|
||||||
var input_json = {
|
var input_json = {
|
||||||
@@ -35,6 +50,7 @@ describe('Serialized object', function() {
|
|||||||
assert.deepEqual(input_json, output_json);
|
assert.deepEqual(input_json, output_json);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#from_json', function() {
|
describe('#from_json', function() {
|
||||||
it('understands TransactionType as a Number', function() {
|
it('understands TransactionType as a Number', function() {
|
||||||
var input_json = {
|
var input_json = {
|
||||||
@@ -52,6 +68,7 @@ describe('Serialized object', function() {
|
|||||||
assert.equal(0, input_json.TransactionType);
|
assert.equal(0, input_json.TransactionType);
|
||||||
assert.equal("Payment", output_json.TransactionType);
|
assert.equal("Payment", output_json.TransactionType);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('understands LedgerEntryType as a Number', function() {
|
it('understands LedgerEntryType as a Number', function() {
|
||||||
var input_json = {
|
var input_json = {
|
||||||
// no, non required fields
|
// no, non required fields
|
||||||
@@ -65,6 +82,7 @@ describe('Serialized object', function() {
|
|||||||
assert.equal(100, input_json.LedgerEntryType);
|
assert.equal(100, input_json.LedgerEntryType);
|
||||||
assert.equal("DirectoryNode", output_json.LedgerEntryType);
|
assert.equal("DirectoryNode", output_json.LedgerEntryType);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Format validation', function() {
|
describe('Format validation', function() {
|
||||||
// Peercover actually had a problem submitting transactions without a `Fee`
|
// Peercover actually had a problem submitting transactions without a `Fee`
|
||||||
// and rippled was only informing of "transaction is invalid"
|
// and rippled was only informing of "transaction is invalid"
|
||||||
@@ -80,15 +98,231 @@ describe('Serialized object', function() {
|
|||||||
};
|
};
|
||||||
assert.throws (
|
assert.throws (
|
||||||
function() {
|
function() {
|
||||||
var output_json = SerializedObject.from_json(input_json);
|
SerializedObject.from_json(input_json);
|
||||||
},
|
},
|
||||||
/Payment is missing fields: \["Fee"\]/
|
/Payment is missing fields: \["Fee"\]/
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
describe('Memos', function() {
|
||||||
|
|
||||||
|
var input_json;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
input_json = {
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"Account": "rhXzSyt1q9J8uiFXpK3qSugAAPJKXLtnrF",
|
||||||
|
"Amount": "1",
|
||||||
|
"Destination": "radqi6ppXFxVhJdjzaATRBxdrPcVTf1Ung",
|
||||||
|
"Sequence": 281,
|
||||||
|
"SigningPubKey": "03D642E6457B8AB4D140E2C66EB4C484FAFB1BF267CB578EC4815FE6CD06379C51",
|
||||||
|
"Fee": "12000",
|
||||||
|
"LastLedgerSequence": 10074214,
|
||||||
|
"TxnSignature": "304402201180636F2CE215CE97A29CD302618FAE60D63EBFC8903DE17A356E857A449C430220290F4A54F9DE4AC79034C8BEA5F1F8757F7505F1A6FF04D2E19B6D62E867256B"
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serialize and parse - full memo, all strings text/plain ', function() {
|
||||||
|
input_json.Memos = [
|
||||||
|
{
|
||||||
|
"Memo": {
|
||||||
|
"MemoType": "test",
|
||||||
|
"MemoFormat": "text",
|
||||||
|
"MemoData": "some data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var so = SerializedObject.from_json(input_json).to_json();
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_format = 'text';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_data = 'some data';
|
||||||
|
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
||||||
|
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('text');
|
||||||
|
input_json.Memos[0].Memo.MemoData = convertStringToHex('some data');
|
||||||
|
|
||||||
|
assert.deepEqual(so, input_json);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serialize and parse - full memo, all strings, invalid MemoFormat', function() {
|
||||||
|
input_json.Memos = [
|
||||||
|
{
|
||||||
|
"Memo": {
|
||||||
|
"MemoType": "test",
|
||||||
|
"MemoFormat": "application/json",
|
||||||
|
"MemoData": "some data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var so = SerializedObject.from_json(input_json).to_json();
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_format = 'application/json';
|
||||||
|
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
||||||
|
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('application/json');
|
||||||
|
input_json.Memos[0].Memo.MemoData = convertStringToHex('some data');
|
||||||
|
|
||||||
|
assert.deepEqual(so, input_json);
|
||||||
|
assert.strictEqual(input_json.Memos[0].Memo.parsed_memo_data, void(0));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error - full memo, json data, invalid MemoFormat', function() {
|
||||||
|
input_json.Memos = [
|
||||||
|
{
|
||||||
|
"Memo": {
|
||||||
|
"MemoType": "test",
|
||||||
|
"MemoFormat": "text",
|
||||||
|
"MemoData": {
|
||||||
|
"string" : "some_string",
|
||||||
|
"boolean" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.throws(function() {
|
||||||
|
SerializedObject.from_json(input_json);
|
||||||
|
}, /^Error: MemoData can only be a JSON object with a valid json MemoFormat \(Memo\) \(Memos\)/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serialize and parse - full memo, json data, valid MemoFormat, ignored field', function() {
|
||||||
|
input_json.Memos = [
|
||||||
|
{
|
||||||
|
"Memo": {
|
||||||
|
"MemoType": "test",
|
||||||
|
"MemoFormat": "json",
|
||||||
|
"ignored" : "ignored",
|
||||||
|
"MemoData": {
|
||||||
|
"string" : "some_string",
|
||||||
|
"boolean" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var so = SerializedObject.from_json(input_json).to_json();
|
||||||
|
delete input_json.Memos[0].Memo.ignored;
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_format = 'json';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_data = {
|
||||||
|
"string" : "some_string",
|
||||||
|
"boolean" : true
|
||||||
|
};
|
||||||
|
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
||||||
|
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('json');
|
||||||
|
input_json.Memos[0].Memo.MemoData = convertStringToHex(JSON.stringify(
|
||||||
|
{
|
||||||
|
"string" : "some_string",
|
||||||
|
"boolean" : true
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.deepEqual(so, input_json);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serialize and parse - full memo, json data, valid MemoFormat', function() {
|
||||||
|
input_json.Memos = [
|
||||||
|
{
|
||||||
|
"Memo": {
|
||||||
|
"MemoType": "test",
|
||||||
|
"MemoFormat": "json",
|
||||||
|
"MemoData": {
|
||||||
|
"string" : "some_string",
|
||||||
|
"boolean" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var so = SerializedObject.from_json(input_json).to_json();
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_format = 'json';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_data = {
|
||||||
|
"string" : "some_string",
|
||||||
|
"boolean" : true
|
||||||
|
};
|
||||||
|
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
||||||
|
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('json');
|
||||||
|
input_json.Memos[0].Memo.MemoData = convertStringToHex(JSON.stringify(
|
||||||
|
{
|
||||||
|
"string" : "some_string",
|
||||||
|
"boolean" : true
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.deepEqual(so, input_json);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serialize and parse - full memo, json data, valid MemoFormat, integer', function() {
|
||||||
|
input_json.Memos = [
|
||||||
|
{
|
||||||
|
"Memo": {
|
||||||
|
"MemoType": "test",
|
||||||
|
"MemoFormat": "json",
|
||||||
|
"MemoData": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var so = SerializedObject.from_json(input_json).to_json();
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_format = 'json';
|
||||||
|
input_json.Memos[0].Memo.parsed_memo_data = 3;
|
||||||
|
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
||||||
|
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('json');
|
||||||
|
input_json.Memos[0].Memo.MemoData = convertStringToHex(JSON.parse(3));
|
||||||
|
assert.deepEqual(so, input_json);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error - invalid Memo field', function() {
|
||||||
|
input_json.Memos = [
|
||||||
|
{
|
||||||
|
"Memo": {
|
||||||
|
"MemoType": "test",
|
||||||
|
"MemoParty": "json",
|
||||||
|
"MemoData": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.throws(function() {
|
||||||
|
SerializedObject.from_json(input_json);
|
||||||
|
}, /^Error: JSON contains unknown field: "MemoParty" \(Memo\) \(Memos\)/);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should serialize json with memo - match hex output', function() {
|
||||||
|
var input_json = {
|
||||||
|
Flags: 2147483648,
|
||||||
|
TransactionType: 'Payment',
|
||||||
|
Account: 'rhXzSyt1q9J8uiFXpK3qSugAAPJKXLtnrF',
|
||||||
|
Amount: '1',
|
||||||
|
Destination: 'radqi6ppXFxVhJdjzaATRBxdrPcVTf1Ung',
|
||||||
|
Memos: [
|
||||||
|
{
|
||||||
|
Memo: {
|
||||||
|
MemoType: 'image'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Sequence: 294,
|
||||||
|
SigningPubKey: '03D642E6457B8AB4D140E2C66EB4C484FAFB1BF267CB578EC4815FE6CD06379C51',
|
||||||
|
Fee: '12000',
|
||||||
|
LastLedgerSequence: 10404607,
|
||||||
|
TxnSignature: '304402206B53EDFA6EFCF6FE5BA76C81BABB60A3B55E9DE8A1462DEDC5F387879575E498022015AE7B59AA49E735D7F2E252802C4406CD00689BCE5057C477FE979D38D2DAC9'
|
||||||
|
};
|
||||||
|
|
||||||
|
var serializedHex = '12000022800000002400000126201B009EC2FF614000000000000001684000000000002EE0732103D642E6457B8AB4D140E2C66EB4C484FAFB1BF267CB578EC4815FE6CD06379C517446304402206B53EDFA6EFCF6FE5BA76C81BABB60A3B55E9DE8A1462DEDC5F387879575E498022015AE7B59AA49E735D7F2E252802C4406CD00689BCE5057C477FE979D38D2DAC9811426C4CFB3BD05A9AA23936F2E81634C66A9820C9483143DD06317D19C6110CAFF150AE528F58843BE2CA1F9EA7C05696D616765E1F1';
|
||||||
|
assert.strictEqual(SerializedObject.from_json(input_json).to_hex(), serializedHex);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// vim:sw=2:sts=2:ts=8:et
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
|
||||||
@@ -1051,26 +1051,84 @@ describe('Transaction', function() {
|
|||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
transaction.addMemo('testkey', 'testvalue');
|
var memoType = 'message';
|
||||||
transaction.addMemo('testkey2', 'testvalue2');
|
var memoFormat = 'application/json';
|
||||||
transaction.addMemo('testkey3');
|
var memoData = {
|
||||||
transaction.addMemo(void(0), 'testvalue4');
|
string: 'value',
|
||||||
|
bool: true,
|
||||||
|
integer: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
transaction.addMemo(memoType, memoFormat, memoData);
|
||||||
|
|
||||||
|
var expected = [
|
||||||
|
{
|
||||||
|
Memo:
|
||||||
|
{
|
||||||
|
MemoType: memoType,
|
||||||
|
MemoFormat: memoFormat,
|
||||||
|
MemoData: memoData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.deepEqual(transaction.tx_json.Memos, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Add Memo - by object', function() {
|
||||||
|
var transaction = new Transaction();
|
||||||
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
|
var memo = {
|
||||||
|
memoType: 'type',
|
||||||
|
memoData: 'data'
|
||||||
|
};
|
||||||
|
|
||||||
|
transaction.addMemo(memo);
|
||||||
|
|
||||||
|
var expected = [
|
||||||
|
{
|
||||||
|
Memo: {
|
||||||
|
MemoType: memo.memoType,
|
||||||
|
MemoData: memo.memoData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.deepEqual(transaction.tx_json.Memos, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Add Memos', function() {
|
||||||
|
var transaction = new Transaction();
|
||||||
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
|
transaction.addMemo('testkey', void(0), 'testvalue');
|
||||||
|
transaction.addMemo('testkey2', void(0), 'testvalue2');
|
||||||
|
transaction.addMemo('testkey3', 'text/html');
|
||||||
|
transaction.addMemo(void(0), void(0), 'testvalue4');
|
||||||
|
transaction.addMemo('testkey4', 'text/html', '<html>');
|
||||||
|
|
||||||
var expected = [
|
var expected = [
|
||||||
{ Memo: {
|
{ Memo: {
|
||||||
MemoType: new Buffer('testkey').toString('hex'),
|
MemoType: 'testkey',
|
||||||
MemoData: new Buffer('testvalue').toString('hex')
|
MemoData: 'testvalue'
|
||||||
}},
|
}},
|
||||||
{ Memo: {
|
{ Memo: {
|
||||||
MemoType: new Buffer('testkey2').toString('hex'),
|
MemoType: 'testkey2',
|
||||||
MemoData: new Buffer('testvalue2').toString('hex')
|
MemoData: 'testvalue2'
|
||||||
}},
|
}},
|
||||||
{ Memo: {
|
{ Memo: {
|
||||||
MemoType: new Buffer('testkey3').toString('hex')
|
MemoType: 'testkey3',
|
||||||
|
MemoFormat: 'text/html'
|
||||||
}},
|
}},
|
||||||
{ Memo: {
|
{ Memo: {
|
||||||
MemoData: new Buffer('testvalue4').toString('hex')
|
MemoData: 'testvalue4'
|
||||||
} }
|
}},
|
||||||
|
{ Memo: {
|
||||||
|
MemoType: 'testkey4',
|
||||||
|
MemoFormat: 'text/html',
|
||||||
|
MemoData: '<html>'
|
||||||
|
}}
|
||||||
];
|
];
|
||||||
|
|
||||||
assert.deepEqual(transaction.tx_json.Memos, expected);
|
assert.deepEqual(transaction.tx_json.Memos, expected);
|
||||||
@@ -1085,13 +1143,76 @@ describe('Transaction', function() {
|
|||||||
}, /^Error: MemoType must be a string$/);
|
}, /^Error: MemoType must be a string$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Add Memo - invalid MemoData', function() {
|
it('Add Memo - invalid ASCII MemoType', function() {
|
||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
transaction.addMemo('key', 1);
|
transaction.addMemo('한국어');
|
||||||
}, /^Error: MemoData must be a string$/);
|
}, /^Error: MemoType must be valid ASCII$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Add Memo - invalid MemoFormat', function() {
|
||||||
|
var transaction = new Transaction();
|
||||||
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
|
assert.throws(function() {
|
||||||
|
transaction.addMemo(void(0), 1);
|
||||||
|
}, /^Error: MemoFormat must be a string$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Add Memo - invalid ASCII MemoFormat', function() {
|
||||||
|
var transaction = new Transaction();
|
||||||
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
|
assert.throws(function() {
|
||||||
|
transaction.addMemo(void(0), 'России');
|
||||||
|
}, /^Error: MemoFormat must be valid ASCII$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Add Memo - MemoData string', function() {
|
||||||
|
var transaction = new Transaction();
|
||||||
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
|
transaction.addMemo({memoData:'some_string'});
|
||||||
|
|
||||||
|
assert.deepEqual(transaction.tx_json.Memos, [
|
||||||
|
{
|
||||||
|
Memo: {
|
||||||
|
MemoData: 'some_string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Add Memo - MemoData complex object', function() {
|
||||||
|
var transaction = new Transaction();
|
||||||
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
|
var memo = {
|
||||||
|
memoData: {
|
||||||
|
string: 'string',
|
||||||
|
int: 1,
|
||||||
|
array: [
|
||||||
|
{
|
||||||
|
string: 'string'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
object: {
|
||||||
|
string: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
transaction.addMemo(memo);
|
||||||
|
|
||||||
|
assert.deepEqual(transaction.tx_json.Memos, [
|
||||||
|
{
|
||||||
|
Memo: {
|
||||||
|
MemoData: memo.memoData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Construct AccountSet transaction', function() {
|
it('Construct AccountSet transaction', function() {
|
||||||
@@ -1268,7 +1389,7 @@ describe('Transaction', function() {
|
|||||||
var bid = '1/USD/rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm';
|
var bid = '1/USD/rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm';
|
||||||
var ask = '1/EUR/rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm';
|
var ask = '1/EUR/rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm';
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var transaction = new Transaction().offerCreate('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', bid, ask);
|
new Transaction().offerCreate('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', bid, ask);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1301,13 +1422,13 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
it('Construct SetRegularKey transaction - invalid account', function() {
|
it('Construct SetRegularKey transaction - invalid account', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var transaction = new Transaction().setRegularKey('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', 'r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
new Transaction().setRegularKey('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', 'r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Construct SetRegularKey transaction - invalid regularKey', function() {
|
it('Construct SetRegularKey transaction - invalid regularKey', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var transaction = new Transaction().setRegularKey('rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', 'xr36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
new Transaction().setRegularKey('rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', 'xr36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user