|
|
|
@@ -1,7 +1,7 @@ |
|
|
|
import * as dotevnv from "dotenv" |
|
|
|
import {toUtf8String,parseUnits,ContractFactory, parseEther,JsonRpcProvider, Contract, JsonRpcSigner, Wallet,ContractTransactionResponse, MaxInt256 |
|
|
|
,Transaction,formatEther, |
|
|
|
ZeroHash,ethers,keccak256 |
|
|
|
ZeroHash,ethers,keccak256,id |
|
|
|
} from 'ethers' |
|
|
|
import {Calulator} from "../inc/calc"; |
|
|
|
import axios from "axios"; |
|
|
|
@@ -13,7 +13,7 @@ import { |
|
|
|
import chalk from "chalk"; |
|
|
|
import {checkReceipt,checkReceipt2, setProvider,getDeploymentAddresses, |
|
|
|
getElapsed, sleep,getBlockInfo} from '../inc/util' |
|
|
|
import { sign } from "crypto"; |
|
|
|
|
|
|
|
dotevnv.config(); |
|
|
|
if (!process.env.RPCURL) { |
|
|
|
console.log(`No rpcur value specified...`) |
|
|
|
@@ -27,33 +27,79 @@ async function getNonce(addr: string): Promise<number> { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function info(symbol: string) { |
|
|
|
async function spareToken(symbol: string , amount: number = 50000) { |
|
|
|
const proxy = getDeploymentAddresses(symbol).address; |
|
|
|
console.log(`토큰 주소 : ${proxy}`); |
|
|
|
|
|
|
|
|
|
|
|
const token = new SecurityToken__factory(issuer).attach(proxy) as SecurityToken; |
|
|
|
await token.connect(admin); |
|
|
|
const adminToken = await token.connect(admin); |
|
|
|
|
|
|
|
const n = await token.decimals(); |
|
|
|
const decimals = Number(n); |
|
|
|
const digit = 10 ** Number(decimals); |
|
|
|
|
|
|
|
const ops = await token.operators(); |
|
|
|
console.log(ops); |
|
|
|
|
|
|
|
let operatorRegistered = false; |
|
|
|
for(let i = 0; i < ops.length; i++) { |
|
|
|
//console.log(`${ops[i].toLocaleLowerCase()} == ${issuer.address.toLocaleLowerCase()}`) |
|
|
|
if( ops[i].toLocaleLowerCase() == issuer.address.toLocaleLowerCase()) { |
|
|
|
operatorRegistered = true; |
|
|
|
} |
|
|
|
} |
|
|
|
if(!operatorRegistered) { |
|
|
|
console.log('issuer not registered as operator .. so register'); |
|
|
|
let ret = await adminToken.grantRole( id('OPERATOR_ROLE'),issuer,{ gasLimit: 20000000}); |
|
|
|
await ret.wait(); |
|
|
|
} |
|
|
|
|
|
|
|
const balance = await token.balanceOf(firstHolder); |
|
|
|
const partitions = await token.getDefaultPartitions(); |
|
|
|
console.log(partitions); |
|
|
|
|
|
|
|
let balance = await token.balanceOf(firstHolder); |
|
|
|
console.log(`initial balance = ${balance}`); |
|
|
|
|
|
|
|
let b = await token.isTokenHolderKYC('0x2071ec931b2567a1418e9bc34b786d654a079b43'); |
|
|
|
let addressesToKyc = []; |
|
|
|
let b = await token.isTokenHolderKYC(firstHolder); |
|
|
|
if(!b) { |
|
|
|
console.log('kyc check first!'); |
|
|
|
return; |
|
|
|
console.log('firstHolder needs to be registered'); |
|
|
|
addressesToKyc.push(firstHolder); |
|
|
|
} |
|
|
|
|
|
|
|
await token.KYCtokenHolders([holder1.address,holder2.address]); |
|
|
|
|
|
|
|
b = await token.isTokenHolderKYC(holder1.address); |
|
|
|
if(!b) { |
|
|
|
console.log('kyc check first!'); |
|
|
|
return; |
|
|
|
console.log('holder1 needs to be registered'); |
|
|
|
addressesToKyc.push(holder1.address); |
|
|
|
} |
|
|
|
b = await token.isTokenHolderKYC(holder2.address); |
|
|
|
if(!b) { |
|
|
|
console.log('holder1 needs to be registered'); |
|
|
|
addressesToKyc.push(holder2.address); |
|
|
|
} |
|
|
|
|
|
|
|
if(addressesToKyc.length != 0) { |
|
|
|
let r = await token.KYCtokenHolders(addressesToKyc); |
|
|
|
await r.wait(); |
|
|
|
} |
|
|
|
// token.grantRole(keccak256('OPERATOR_ROLE'),'0xaaa') |
|
|
|
|
|
|
|
balance = await token.balanceOf(holder1); |
|
|
|
let fixedBalance = (1/digit) * Number(balance); |
|
|
|
console.log(`holder1(${holder1.address}) balance = ${fixedBalance.toFixed(decimals)}`); |
|
|
|
if(Number(balance) == 0) { |
|
|
|
console.log('holder1 needs to be filled..'); |
|
|
|
let r = await token.operatorTransferByPartition(partitions[0],firstHolder,holder1, amount * digit,ZeroHash,ZeroHash,{gasLimit: 20000000}); |
|
|
|
await r.wait(); |
|
|
|
} |
|
|
|
balance = await token.balanceOf(holder2); |
|
|
|
fixedBalance = (1/digit) * Number(balance); |
|
|
|
console.log(`holder2(${holder2.address}) balance = ${fixedBalance.toFixed(decimals)}`); |
|
|
|
if(Number(balance) == 0) { |
|
|
|
console.log('holder2 needs to be filled..'); |
|
|
|
let r = await token.operatorTransferByPartition(partitions[0],firstHolder,holder2, amount * digit,ZeroHash,ZeroHash,{gasLimit: 20000000}); |
|
|
|
await r.wait(); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
function getAuthHeader(token: string) : any{ |
|
|
|
@@ -97,6 +143,13 @@ async function send(signedTransaction: string) { |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
async function sign(tx: Transaction,signer: Wallet) : Promise<any> { |
|
|
|
|
|
|
|
const signed = await signer.signTransaction(tx); |
|
|
|
|
|
|
|
return {nonce: tx.nonce, sig: signed , txid: keccak256(signed)} |
|
|
|
} |
|
|
|
|
|
|
|
async function transfer(signer: Wallet,symbol:string,from: Wallet, to: Wallet, amount: number = 1, count: number = 10) { |
|
|
|
const proxy = getDeploymentAddresses(symbol).address; |
|
|
|
console.log(`토큰 주소 : ${proxy}`); |
|
|
|
@@ -104,8 +157,6 @@ async function transfer(signer: Wallet,symbol:string,from: Wallet, to: Wallet, a |
|
|
|
const token = new SecurityToken__factory(issuer).attach(proxy) as SecurityToken; |
|
|
|
const decimals = await token.decimals(); |
|
|
|
const digit = 10 ** Number(decimals); |
|
|
|
//console.log(`자릿수 = ${digit}`); |
|
|
|
|
|
|
|
|
|
|
|
let fb = await getBalance(symbol,from.address); |
|
|
|
let tb = await getBalance(symbol,to.address); |
|
|
|
@@ -116,45 +167,58 @@ async function transfer(signer: Wallet,symbol:string,from: Wallet, to: Wallet, a |
|
|
|
|
|
|
|
let firstTx:string = null; |
|
|
|
let lastTx:string = null; |
|
|
|
const start = Date.now(); |
|
|
|
let start = Date.now(); |
|
|
|
console.log(chalk.cyan(`전송시작 시간 : ${new Date(start).toUTCString()}`)); |
|
|
|
|
|
|
|
console.log(chalk.yellow(`sending ${count} transactions`)); |
|
|
|
let signedData = []; |
|
|
|
|
|
|
|
let unsignedProms = []; |
|
|
|
for(let i = 0; i < count; i++) { |
|
|
|
const rawTx = await getTx(signer.address,symbol,from.address,to.address, amount * digit); |
|
|
|
const tx = Transaction.from(rawTx.data); |
|
|
|
const signed = await signer.signTransaction(tx); |
|
|
|
signedData.push(signed); |
|
|
|
|
|
|
|
if(i == 0) { |
|
|
|
firstTx = keccak256(signed); |
|
|
|
} else if(i == count -1) { |
|
|
|
lastTx = keccak256(signed); |
|
|
|
} |
|
|
|
unsignedProms.push(getTx(signer.address,symbol,from.address,to.address, amount * digit)); |
|
|
|
} |
|
|
|
|
|
|
|
// const start = Date.now(); |
|
|
|
// console.log(chalk.cyan(`전송시작 시간 : ${new Date(start).toUTCString()}`)); |
|
|
|
|
|
|
|
let txMap = new Map<string,boolean>(); |
|
|
|
let unsigned = await Promise.all(unsignedProms); |
|
|
|
let signedProms = []; |
|
|
|
unsigned.forEach(u => { |
|
|
|
const tx = Transaction.from(u.data); |
|
|
|
signedProms.push(sign(tx,signer)); |
|
|
|
}); |
|
|
|
let signedData = await Promise.all(signedProms); |
|
|
|
const elapsed = getElapsed(start,1000); |
|
|
|
console.log(`TxPrepared within ${elapsed} seconds`); |
|
|
|
console.log(chalk.yellow(`sending ${count} transactions`)); |
|
|
|
|
|
|
|
start = Date.now(); |
|
|
|
console.log(chalk.cyan(`실제 전송시작 시간 : ${new Date(start).toUTCString()}`)); |
|
|
|
|
|
|
|
let proms = []; |
|
|
|
for(let i = 0; i < count; i++) { |
|
|
|
proms.push(send(signedData[i])); |
|
|
|
console.log(`sending ${i} , nonce : ${signedData[i].nonce}`); |
|
|
|
proms.push(send(signedData[i].sig)); |
|
|
|
} |
|
|
|
|
|
|
|
let resolved = await Promise.all(proms); |
|
|
|
|
|
|
|
|
|
|
|
let txMap = new Map<string,boolean>(); |
|
|
|
resolved.forEach(tx => { |
|
|
|
txMap.set(tx.data.transactionHash,false) |
|
|
|
//console.log(tx.data.transactionHash); |
|
|
|
}); |
|
|
|
|
|
|
|
console.log(`sent txid count = ${txMap.size}`); |
|
|
|
|
|
|
|
let nonce = 0; |
|
|
|
signedData.forEach( tx => { |
|
|
|
if(tx.nonce > nonce) { |
|
|
|
lastTx = tx.txid; |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
const blockHashes = await checkReceipt2(txMap,[firstTx as string, lastTx as string], 'wait for receipt...'); |
|
|
|
const firstBlockHash = blockHashes.get(firstTx); |
|
|
|
//const firstBlockHash = blockHashes.get(firstTx); |
|
|
|
const lastBlockHash = blockHashes.get(lastTx); |
|
|
|
console.log(`firstBlockHash = ${firstBlockHash} \nlastBlockHash = ${lastBlockHash}`); |
|
|
|
//console.log(`firstBlockHash = ${firstBlockHash} \nlastBlockHash = ${lastBlockHash}`); |
|
|
|
console.log(`lastBlockHash = ${lastBlockHash}`); |
|
|
|
|
|
|
|
fb = await getBalance(symbol,from.address); |
|
|
|
tb = await getBalance(symbol,to.address); |
|
|
|
@@ -163,8 +227,6 @@ async function transfer(signer: Wallet,symbol:string,from: Wallet, to: Wallet, a |
|
|
|
console.log(chalk.yellow('###################### 전송후 잔고 ###################################')) |
|
|
|
console.log(`balance of sender(${from.address}) = ${fb.toFixed(Number(decimals))}\r\nbalance of receiver(${to.address}) = ${tb.toFixed(Number(decimals))}`); |
|
|
|
|
|
|
|
console.log(firstTx); |
|
|
|
|
|
|
|
const lastB = await getBlockInfo(lastBlockHash); |
|
|
|
const lastTimeStamp = parseInt(lastB.timestamp,16); |
|
|
|
console.log(`eth_getBlockByHash(${lastBlockHash}).timestamp = ${lastTimeStamp}`) |
|
|
|
@@ -181,7 +243,7 @@ async function transfer(signer: Wallet,symbol:string,from: Wallet, to: Wallet, a |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const firstHolder = '0x2071ec931b2567a1418e9bc34b786d654a079b43'; |
|
|
|
const firstHolder = '0x3050C8Eab31E2cbB6d29683f831CaB2FD52a9872'; |
|
|
|
const calc = new Calulator(); |
|
|
|
const rpcUrl = process.env.RPCURL; |
|
|
|
const gateWay = process.env.GATE_WAY; |
|
|
|
@@ -199,7 +261,8 @@ const holder2 = new Wallet('0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae |
|
|
|
console.log(`목적 서버 : ${gateWay}`); |
|
|
|
|
|
|
|
async function main() { |
|
|
|
transfer(holder1,'BCG_TEST',holder1, holder2,1, 1000); |
|
|
|
//spareToken('BCG_TEST'); |
|
|
|
transfer(holder1,'BCG_TEST',holder2, holder1,1, 4); |
|
|
|
} |
|
|
|
|
|
|
|
main(); |