@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
116 lines (111 loc) • 4.33 kB
JavaScript
import { Buffer as _Buffer } from "buffer";
import AccountBase from './Base.js';
import { ArgumentError, NotImplementedError } from '../utils/errors.js';
import { decode } from '../utils/encoder.js';
import { buildTx } from '../tx/builder/index.js';
import { Tag } from '../tx/builder/constants.js';
export const CLA = 0xe0;
export const GET_ADDRESS = 0x02;
export const SIGN_TRANSACTION = 0x04;
export const GET_APP_CONFIGURATION = 0x06;
export const SIGN_PERSONAL_MESSAGE = 0x08;
/**
* Ledger wallet account class
* @category account
*/
export default class AccountLedger extends AccountBase {
/**
* @param transport - Connection to Ledger to use
* @param index - Index of account
* @param address - Address of account
*/
constructor(transport, index, address) {
super();
this.transport = transport;
this.index = index;
this.address = address;
transport.decorateAppAPIMethods(this, ['signTransaction', 'signMessage'], 'w0w');
}
/**
* @deprecated Use `unsafeSign` method instead
*/
// eslint-disable-next-line class-methods-use-this
async sign() {
return this.unsafeSign();
}
// eslint-disable-next-line class-methods-use-this
async unsafeSign() {
throw new NotImplementedError('RAW signing using Ledger HW');
}
// eslint-disable-next-line class-methods-use-this
async signTypedData() {
throw new NotImplementedError('Typed data signing using Ledger HW');
}
// eslint-disable-next-line class-methods-use-this
async signDelegation() {
throw new NotImplementedError('signing delegation using Ledger HW');
}
async signTransaction(tx, {
innerTx,
networkId
} = {}) {
if (innerTx != null) throw new NotImplementedError('innerTx option in AccountLedger');
if (networkId == null) throw new ArgumentError('networkId', 'provided', networkId);
const rawTx = decode(tx);
let offset = 0;
const headerLength = 4 + 1 + 4;
const networkIdBuffer = _Buffer.from(networkId);
const toSend = [];
while (offset !== rawTx.length) {
const maxChunkSize = offset === 0 ? 150 - headerLength - networkIdBuffer.length : 150;
const chunkSize = offset + maxChunkSize > rawTx.length ? rawTx.length - offset : maxChunkSize;
const buffer = _Buffer.alloc(offset === 0 ? headerLength + networkIdBuffer.length + chunkSize : chunkSize);
if (offset === 0) {
let bufferOffset = buffer.writeUInt32BE(this.index, 0);
bufferOffset = buffer.writeUInt32BE(rawTx.length, bufferOffset);
bufferOffset = buffer.writeUInt8(networkIdBuffer.length, bufferOffset);
bufferOffset += networkIdBuffer.copy(buffer, bufferOffset, 0, networkIdBuffer.length);
rawTx.copy(buffer, bufferOffset, 0, 150 - bufferOffset);
} else {
rawTx.copy(buffer, 0, offset, offset + chunkSize);
}
toSend.push(buffer);
offset += chunkSize;
}
const response = await toSend.reduce(async (previous, data, i) => {
await previous;
return this.transport.send(CLA, SIGN_TRANSACTION, i === 0 ? 0x00 : 0x80, 0x00, data);
}, Promise.resolve(_Buffer.alloc(0)));
const signatures = [response.subarray(0, 64)];
return buildTx({
tag: Tag.SignedTx,
encodedTx: rawTx,
signatures
});
}
async signMessage(messageStr) {
let offset = 0;
const message = _Buffer.from(messageStr);
const toSend = [];
while (offset !== message.length) {
const maxChunkSize = offset === 0 ? 150 - 4 - 4 : 150;
const chunkSize = offset + maxChunkSize > message.length ? message.length - offset : maxChunkSize;
const buffer = _Buffer.alloc(offset === 0 ? 4 + 4 + chunkSize : chunkSize);
if (offset === 0) {
buffer.writeUInt32BE(this.index, 0);
buffer.writeUInt32BE(message.length, 4);
message.copy(buffer, 4 + 4, offset, offset + chunkSize);
} else {
message.copy(buffer, 0, offset, offset + chunkSize);
}
toSend.push(buffer);
offset += chunkSize;
}
const response = await toSend.reduce(async (previous, data, i) => {
await previous;
return this.transport.send(CLA, SIGN_PERSONAL_MESSAGE, i === 0 ? 0x00 : 0x80, 0x00, data);
}, Promise.resolve(_Buffer.alloc(0)));
return response.subarray(0, 64);
}
}
//# sourceMappingURL=Ledger.js.map