Add method for sending transfer requests.
This commit is contained in:
@@ -6,6 +6,14 @@ import {environment} from '@src/environments/environment';
|
||||
import {User} from 'cic-client-meta';
|
||||
import {UserService} from '@app/_services/user.service';
|
||||
import { AccountIndex } from '@app/_helpers';
|
||||
import { Keccak } from 'sha3';
|
||||
import { utils } from 'ethers';
|
||||
import {add0x, fromHex, strip0x, toHex} from '@src/assets/js/ethtx/dist/hex';
|
||||
import {Tx} from '@src/assets/js/ethtx/dist';
|
||||
import {toValue} from '@src/assets/js/ethtx/dist/tx';
|
||||
import * as secp256k1 from 'secp256k1';
|
||||
import {AuthService} from '@app/_services/auth.service';
|
||||
const Web3 = require('web3');
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -16,9 +24,11 @@ export class TransactionService {
|
||||
transactionsSubject = this.transactionList.asObservable();
|
||||
userInfo: any;
|
||||
request = new AccountIndex(environment.contractAddress);
|
||||
web3 = new Web3(environment.web3Provider);
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private authService: AuthService,
|
||||
private userService: UserService
|
||||
) { }
|
||||
|
||||
@@ -74,14 +84,36 @@ export class TransactionService {
|
||||
this.userInfo = this.userService.getUser(await User.toKey(address));
|
||||
}
|
||||
|
||||
transferRequest(tokenAddress: string, senderAddress: string, recipientAddress: string, value: number): Observable<any> {
|
||||
return this.http.post(
|
||||
`${environment.cicEthUrl}/transfer`,
|
||||
{
|
||||
tokenAddress: tokenAddress,
|
||||
from: senderAddress,
|
||||
to: recipientAddress,
|
||||
value: value,
|
||||
});
|
||||
async transferRequest(tokenAddress: string, senderAddress: string, recipientAddress: string, value: number): Promise<any> {
|
||||
const hashFunction = new Keccak(256);
|
||||
hashFunction.update('createRequest(address,address,address,uint256)');
|
||||
const hash = hashFunction.digest();
|
||||
const methodSignature = hash.toString('hex').substring(0, 8);
|
||||
const abiCoder = new utils.AbiCoder();
|
||||
const abi = await abiCoder.encode(['address', 'address', 'address', 'uint256'], [senderAddress, recipientAddress, tokenAddress, value]);
|
||||
const data = fromHex(methodSignature + strip0x(abi));
|
||||
const tx = new Tx(environment.bloxbergChainId);
|
||||
tx.nonce = await this.web3.eth.getTransactionCount(senderAddress);
|
||||
tx.gasPrice = await this.web3.eth.getGasPrice();
|
||||
tx.gasLimit = 8000000;
|
||||
tx.to = fromHex(strip0x(recipientAddress));
|
||||
tx.value = toValue(value);
|
||||
tx.data = data;
|
||||
const txMsg = tx.message();
|
||||
const privateKey = this.authService.mutableKeyStore.getPrivateKey();
|
||||
if (!privateKey.isDecrypted()) {
|
||||
const password = window.prompt('password');
|
||||
await privateKey.decrypt(password);
|
||||
}
|
||||
const signatureObject = secp256k1.ecdsaSign(txMsg, privateKey.keyPacket.privateParams.d);
|
||||
const r = signatureObject.signature.slice(0, 32);
|
||||
const s = signatureObject.signature.slice(32);
|
||||
const v = signatureObject.recid;
|
||||
tx.setSignature(r, s, v);
|
||||
const txWire = add0x(toHex(tx.serializeRLP()));
|
||||
const result = await this.web3.eth.sendSignedTransaction(txWire);
|
||||
console.log('Result', result);
|
||||
const transaction = await this.web3.eth.getTransaction(result.transactionHash);
|
||||
console.log('Transaction', transaction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,18 +31,16 @@ export class DisbursementComponent implements OnInit {
|
||||
|
||||
get disbursementFormStub(): any { return this.disbursementForm.controls; }
|
||||
|
||||
createTransfer(): void {
|
||||
async createTransfer(): Promise<void> {
|
||||
this.submitted = true;
|
||||
if (this.disbursementForm.invalid) { return; }
|
||||
if (this.disbursementFormStub.transactionType.value === 'transfer') {
|
||||
this.transactionService.transferRequest(
|
||||
await this.transactionService.transferRequest(
|
||||
this.account.token,
|
||||
this.account.address,
|
||||
this.disbursementFormStub.recipient.value,
|
||||
this.disbursementFormStub.amount.value
|
||||
).pipe(first()).subscribe(res => {
|
||||
console.log(res);
|
||||
});
|
||||
);
|
||||
}
|
||||
console.log(this.disbursementFormStub.transactionType.value);
|
||||
this.submitted = false;
|
||||
|
||||
5
src/assets/js/ethtx/dist/hex.d.ts
vendored
Normal file
5
src/assets/js/ethtx/dist/hex.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
declare function strip0x(hexString: string): string;
|
||||
declare function add0x(hexString: string): string;
|
||||
declare function fromHex(hexString: string): Uint8Array;
|
||||
declare function toHex(bytes: Uint8Array): string;
|
||||
export { fromHex, toHex, strip0x, add0x, };
|
||||
41
src/assets/js/ethtx/dist/hex.js
vendored
Normal file
41
src/assets/js/ethtx/dist/hex.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.add0x = exports.strip0x = exports.toHex = exports.fromHex = void 0;
|
||||
// improve
|
||||
function validHex(hexString) {
|
||||
return hexString;
|
||||
}
|
||||
function even(hexString) {
|
||||
if (hexString.length % 2 != 0) {
|
||||
hexString = '0' + hexString;
|
||||
}
|
||||
return hexString;
|
||||
}
|
||||
function strip0x(hexString) {
|
||||
if (hexString.length < 2) {
|
||||
throw new Error('invalid hex');
|
||||
}
|
||||
else if (hexString.substring(0, 2) == '0x') {
|
||||
hexString = hexString.substring(2);
|
||||
}
|
||||
return validHex(even(hexString));
|
||||
}
|
||||
exports.strip0x = strip0x;
|
||||
function add0x(hexString) {
|
||||
if (hexString.length < 2) {
|
||||
throw new Error('invalid hex');
|
||||
}
|
||||
else if (hexString.substring(0, 2) != '0x') {
|
||||
hexString = '0x' + hexString;
|
||||
}
|
||||
return validHex(even(hexString));
|
||||
}
|
||||
exports.add0x = add0x;
|
||||
function fromHex(hexString) {
|
||||
return new Uint8Array(hexString.match(/.{1,2}/g).map(function (byte) { return parseInt(byte, 16); }));
|
||||
}
|
||||
exports.fromHex = fromHex;
|
||||
function toHex(bytes) {
|
||||
return bytes.reduce(function (str, byte) { return str + byte.toString(16).padStart(2, '0'); }, '');
|
||||
}
|
||||
exports.toHex = toHex;
|
||||
1
src/assets/js/ethtx/dist/index.d.ts
vendored
Normal file
1
src/assets/js/ethtx/dist/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { Tx } from './tx';
|
||||
5
src/assets/js/ethtx/dist/index.js
vendored
Normal file
5
src/assets/js/ethtx/dist/index.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Tx = void 0;
|
||||
var tx_1 = require("./tx");
|
||||
Object.defineProperty(exports, "Tx", { enumerable: true, get: function () { return tx_1.Tx; } });
|
||||
29
src/assets/js/ethtx/dist/tx.d.ts
vendored
Normal file
29
src/assets/js/ethtx/dist/tx.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
declare function toValue(n: number): bigint;
|
||||
declare function stringToValue(s: string): bigint;
|
||||
declare function hexToValue(hx: string): bigint;
|
||||
declare class Tx {
|
||||
nonce: number;
|
||||
gasPrice: number;
|
||||
gasLimit: number;
|
||||
to: Uint8Array;
|
||||
value: bigint;
|
||||
data: Uint8Array;
|
||||
v: number;
|
||||
r: Uint8Array;
|
||||
s: Uint8Array;
|
||||
chainId: number;
|
||||
_signatureSet: boolean;
|
||||
_workBuffer: ArrayBuffer;
|
||||
_outBuffer: DataView;
|
||||
_outBufferCursor: number;
|
||||
constructor(chainId: number);
|
||||
private serializeNumber;
|
||||
private write;
|
||||
serializeBytes(): Uint8Array;
|
||||
canonicalOrder(): Uint8Array[];
|
||||
serializeRLP(): Uint8Array;
|
||||
message(): Uint8Array;
|
||||
setSignature(r: Uint8Array, s: Uint8Array, v: number): void;
|
||||
clearSignature(): void;
|
||||
}
|
||||
export { Tx, stringToValue, hexToValue, toValue, };
|
||||
121
src/assets/js/ethtx/dist/tx.js
vendored
Normal file
121
src/assets/js/ethtx/dist/tx.js
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.toValue = exports.hexToValue = exports.stringToValue = exports.Tx = void 0;
|
||||
var hex_1 = require("./hex");
|
||||
var sha3_1 = require("sha3");
|
||||
var RLP = require('rlp');
|
||||
function isAddress(a) {
|
||||
return a !== undefined && a.length == 20;
|
||||
}
|
||||
function toValue(n) {
|
||||
return BigInt(n);
|
||||
}
|
||||
exports.toValue = toValue;
|
||||
function stringToValue(s) {
|
||||
return BigInt(s);
|
||||
}
|
||||
exports.stringToValue = stringToValue;
|
||||
function hexToValue(hx) {
|
||||
return BigInt(hex_1.add0x(hx));
|
||||
}
|
||||
exports.hexToValue = hexToValue;
|
||||
var Tx = /** @class */ (function () {
|
||||
function Tx(chainId) {
|
||||
this.chainId = chainId;
|
||||
this.nonce = 0;
|
||||
this.gasPrice = 0;
|
||||
this.gasLimit = 0;
|
||||
this.to = new Uint8Array(32);
|
||||
this.data = new Uint8Array(0);
|
||||
this.value = BigInt(0);
|
||||
this._workBuffer = new ArrayBuffer(32);
|
||||
this._outBuffer = new DataView(new ArrayBuffer(1024 * 1024));
|
||||
this._outBufferCursor = 0;
|
||||
this.clearSignature();
|
||||
}
|
||||
Tx.prototype.serializeNumber = function (n) {
|
||||
var view = new DataView(this._workBuffer);
|
||||
view.setBigUint64(0, BigInt(0));
|
||||
view.setBigUint64(0, n);
|
||||
var zeroOffset = 0;
|
||||
for (zeroOffset = 0; zeroOffset < 8; zeroOffset++) {
|
||||
if (view.getInt8(zeroOffset) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new Uint8Array(this._workBuffer).slice(zeroOffset, 8);
|
||||
};
|
||||
Tx.prototype.write = function (data) {
|
||||
var _this = this;
|
||||
data.forEach(function (v) {
|
||||
_this._outBuffer.setInt8(_this._outBufferCursor, v);
|
||||
_this._outBufferCursor++;
|
||||
});
|
||||
};
|
||||
Tx.prototype.serializeBytes = function () {
|
||||
if (!isAddress(this.to)) {
|
||||
throw new Error('invalid address');
|
||||
}
|
||||
var nonce = this.serializeNumber(BigInt(this.nonce));
|
||||
this.write(nonce);
|
||||
var gasPrice = this.serializeNumber(BigInt(this.gasPrice));
|
||||
this.write(gasPrice);
|
||||
var gasLimit = this.serializeNumber(BigInt(this.gasLimit));
|
||||
this.write(gasLimit);
|
||||
this.write(this.to);
|
||||
var value = this.serializeNumber(this.value);
|
||||
this.write(value);
|
||||
this.write(this.data);
|
||||
var v = this.serializeNumber(BigInt(this.v));
|
||||
this.write(v);
|
||||
this.write(this.r);
|
||||
this.write(this.s);
|
||||
return new Uint8Array(this._outBuffer.buffer).slice(0, this._outBufferCursor);
|
||||
};
|
||||
Tx.prototype.canonicalOrder = function () {
|
||||
return [
|
||||
this.serializeNumber(BigInt(this.nonce)),
|
||||
this.serializeNumber(BigInt(this.gasPrice)),
|
||||
this.serializeNumber(BigInt(this.gasLimit)),
|
||||
this.to,
|
||||
this.serializeNumber(this.value),
|
||||
this.data,
|
||||
this.serializeNumber(BigInt(this.v)),
|
||||
this.r,
|
||||
this.s,
|
||||
];
|
||||
};
|
||||
Tx.prototype.serializeRLP = function () {
|
||||
return RLP.encode(this.canonicalOrder());
|
||||
};
|
||||
Tx.prototype.message = function () {
|
||||
// TODO: Can we do without Buffer, pleeease?
|
||||
var h = new sha3_1.Keccak(256);
|
||||
var b = new Buffer(this.serializeRLP());
|
||||
h.update(b);
|
||||
return h.digest();
|
||||
};
|
||||
Tx.prototype.setSignature = function (r, s, v) {
|
||||
if (this._signatureSet) {
|
||||
throw new Error('Signature already set');
|
||||
}
|
||||
if (r.length != 32 || s.length != 32) {
|
||||
throw new Error('Invalid signature length');
|
||||
}
|
||||
if (v < 0 || v > 3) {
|
||||
throw new Error('Invalid recid');
|
||||
}
|
||||
this.r = r;
|
||||
this.s = s;
|
||||
this.v = (this.chainId * 2) + 35 + v;
|
||||
this._signatureSet = true;
|
||||
};
|
||||
Tx.prototype.clearSignature = function () {
|
||||
this.r = new Uint8Array(0);
|
||||
this.s = new Uint8Array(0);
|
||||
this.v = this.chainId;
|
||||
this._signatureSet = false;
|
||||
};
|
||||
return Tx;
|
||||
}());
|
||||
exports.Tx = Tx;
|
||||
@@ -1,5 +1,6 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
bloxbergChainId: 8996,
|
||||
cicAuthUrl: 'http://localhost:4444',
|
||||
cicMetaUrl: 'http://localhost:63380',
|
||||
publicKeysUrl: 'http://localhost:8000',
|
||||
@@ -10,5 +11,6 @@ export const environment = {
|
||||
cicEthUrl: 'http://localhost:63314',
|
||||
contractAddress: '0xd0097a901AF4ac2E63A5b6E86be8Ad91f10b05d7',
|
||||
registryAddress: '0xf374d7B507767101a4bf3bA2a6B99AC737A44f6d',
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C'
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C',
|
||||
transferAuthorizationAddress: '0xB542fd8bCb777f058997b7D8D06381A0571BF224'
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
bloxbergChainId: 8996,
|
||||
cicAuthUrl: 'http://localhost:4444',
|
||||
cicMetaUrl: 'http://localhost:63380',
|
||||
publicKeysUrl: 'http://localhost:8000',
|
||||
@@ -14,7 +15,8 @@ export const environment = {
|
||||
cicEthUrl: 'http://localhost:63314',
|
||||
contractAddress: '0xd0097a901AF4ac2E63A5b6E86be8Ad91f10b05d7',
|
||||
registryAddress: '0xf374d7B507767101a4bf3bA2a6B99AC737A44f6d',
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C'
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C',
|
||||
transferAuthorizationAddress: '0xB542fd8bCb777f058997b7D8D06381A0571BF224'
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user