|
import * as fs from 'fs'; |
|
import * as glob from 'glob'; |
|
import fetch from 'node-fetch'; |
|
import * as log from 'loglevel'; |
|
|
|
import { BigNumber } from 'bignumber.js'; |
|
|
|
import { registerFetch, registerLogger } from 'conseiljs'; |
|
|
|
import { TezosConstants, TezosConseilClient, TezosNodeWriter, TezosParameterFormat, KeyStore, TezosNodeReader, TezosContractIntrospector, Signer, TezosMessageUtils } from 'conseiljs'; |
|
import { KeyStoreUtils, SoftSigner } from 'conseiljs-softsigner'; |
|
|
|
const tezosNode = '<tezos-node-url>'; |
|
const conseilServer = { url: '<conseil-indexer-url>', apiKey: '<APIKEY_from_nautuilus.cloud>', network: 'edonet' }; |
|
const networkBlockTime = 30 + 1; |
|
|
|
function clearRPCOperationGroupHash(hash: string) { |
|
return hash.replace(/\"/g, '').replace(/\n/, ''); |
|
} |
|
|
|
function initConseil() { |
|
const logger = log.getLogger('conseiljs'); |
|
logger.setLevel('debug', false); |
|
registerLogger(logger); |
|
registerFetch(fetch); |
|
} |
|
|
|
async function initAccount(): Promise<KeyStore> { |
|
console.log('~~ initAccount'); |
|
let faucetFiles: string[] = glob.sync('tz1*.json'); |
|
|
|
if (faucetFiles.length === 0) { |
|
throw new Error('Did not find any faucet files, please go to faucet.tzalpha.net to get one'); |
|
} |
|
|
|
console.log(`loading ${faucetFiles[0]} faucet file`); |
|
let faucetAccount = JSON.parse(fs.readFileSync(faucetFiles[0], 'utf8')); |
|
|
|
let keyStore: KeyStore; |
|
if (faucetAccount['secretKey']) { |
|
keyStore = await KeyStoreUtils.restoreIdentityFromSecretKey(faucetAccount['secretKey']); |
|
} else { |
|
keyStore = await KeyStoreUtils.restoreIdentityFromFundraiser(faucetAccount['mnemonic'].join(' '), faucetAccount['email'], faucetAccount['password'], faucetAccount['pkh']); |
|
faucetAccount['secretKey'] = keyStore.secretKey; |
|
fs.writeFileSync(faucetFiles[0], JSON.stringify(faucetAccount)); |
|
} |
|
|
|
console.log(`public key: ${keyStore.publicKey}`); |
|
console.log(`secret key: ${keyStore.secretKey}`); |
|
console.log(`account hash: ${keyStore.publicKeyHash}`); |
|
console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); |
|
|
|
return keyStore; |
|
} |
|
|
|
async function activateAccount(signer: Signer, keyStore: KeyStore): Promise<string> { |
|
console.log(`~~ activateAccount`); |
|
const accountRecord = await TezosConseilClient.getAccount(conseilServer, conseilServer.network, keyStore.publicKeyHash); |
|
if (accountRecord !== undefined) { return accountRecord['account_id']; } |
|
|
|
const faucetAccount = JSON.parse(fs.readFileSync(`${keyStore.publicKeyHash}.json`, 'utf8')); |
|
|
|
const nodeResult = await TezosNodeWriter.sendIdentityActivationOperation(tezosNode, signer, keyStore, faucetAccount['secret']); |
|
const groupid = clearRPCOperationGroupHash(nodeResult.operationGroupID); |
|
console.log(`Injected activation operation with ${groupid}`); |
|
|
|
const conseilResult = await TezosConseilClient.awaitOperationConfirmation(conseilServer, conseilServer.network, groupid, 5, networkBlockTime); |
|
console.log(`Activated account at ${conseilResult.pkh}`); |
|
console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); |
|
|
|
return conseilResult.pkh; |
|
} |
|
|
|
async function revealAccount(signer: Signer, keyStore: KeyStore): Promise<string> { |
|
console.log(`~~ revealAccount`); |
|
if (await TezosNodeReader.isManagerKeyRevealedForAccount(tezosNode, keyStore.publicKeyHash)) { |
|
return keyStore.publicKeyHash; |
|
} |
|
|
|
const nodeResult = await TezosNodeWriter.sendKeyRevealOperation(tezosNode, signer, keyStore); |
|
const groupid = clearRPCOperationGroupHash(nodeResult.operationGroupID); |
|
console.log(`Injected reveal operation with ${groupid}`); |
|
|
|
const conseilResult = await TezosConseilClient.awaitOperationConfirmation(conseilServer, conseilServer.network, groupid, 5, networkBlockTime); |
|
console.log(`Revealed account at ${conseilResult.source}`); |
|
console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); |
|
|
|
return conseilResult.source; |
|
} |
|
|
|
async function sendTransaction(signer: Signer, keyStore: KeyStore, destination: string, amount: number) { |
|
console.log(`~~ sendTransaction: ${amount}µtz from ${keyStore.publicKeyHash} to ${destination}`); |
|
const nodeResult = await TezosNodeWriter.sendTransactionOperation(tezosNode, signer, keyStore, destination, amount, 100_000, TezosConstants.HeadBranchOffset, true); |
|
const groupid = clearRPCOperationGroupHash(nodeResult.operationGroupID); |
|
console.log(`Injected transaction operation with ${groupid}`); |
|
|
|
const conseilResult = await TezosConseilClient.awaitOperationConfirmation(conseilServer, conseilServer.network, groupid, 5, networkBlockTime); |
|
console.log(`Completed transfer of ${conseilResult.amount}µtz`); |
|
console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); |
|
} |
|
|
|
async function delegateAccount(signer: Signer, keyStore: KeyStore, baker: string) { |
|
console.log(`~~ delegatePrimaryAccount`); |
|
const nodeResult = await TezosNodeWriter.sendDelegationOperation(tezosNode, signer, keyStore, baker, 400, 54, true); |
|
const groupid = clearRPCOperationGroupHash(nodeResult.operationGroupID); |
|
console.log(`Injected delegation operation with ${groupid}`); |
|
|
|
await TezosConseilClient.awaitOperationConfirmation(conseilServer, conseilServer.network, groupid, 5, networkBlockTime); |
|
console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); |
|
} |
|
|
|
async function deployMichelineContract(signer: Signer, keyStore: KeyStore, amount: number, baker: string | undefined): Promise<string> { |
|
console.log(`~~ deployMichelineContract`); |
|
const contract = `[ |
|
{ "prim":"parameter", "args":[ { "prim":"string" } ] }, |
|
{ "prim":"storage", "args":[ { "prim":"string" } ] }, |
|
{ |
|
"prim":"code", |
|
"args":[ |
|
[ |
|
{ "prim":"CAR" }, |
|
{ "prim":"NIL", "args":[ { "prim":"operation" } ] }, |
|
{ "prim":"PAIR" } |
|
] |
|
] |
|
} |
|
]`; |
|
const storage = '{"string": "Sample"}'; |
|
|
|
const nodeResult = await TezosNodeWriter.sendContractOriginationOperation(tezosNode, signer, keyStore, amount, baker, 1000, 1000, 100000, contract, storage, TezosParameterFormat.Micheline, 54, true); |
|
const groupid = clearRPCOperationGroupHash(nodeResult['operationGroupID']); |
|
console.log(`Injected origination operation with ${groupid}`); |
|
|
|
const conseilResult = await TezosConseilClient.awaitOperationConfirmation(conseilServer, conseilServer.network, groupid, 5, networkBlockTime); |
|
console.log(`Originated contract at ${conseilResult.originated_contracts}`); |
|
console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); |
|
|
|
return conseilResult.originated_contracts; |
|
} |
|
|
|
async function deployMichelsonContract(signer: Signer, keyStore: KeyStore, amount: number, baker: string | undefined): Promise<string> { |
|
console.log(`~~ deployMichelsonContract`); |
|
const contract = `parameter string; |
|
storage string; |
|
code { DUP; |
|
DIP { CDR ; NIL string ; SWAP ; CONS } ; |
|
CAR ; CONS ; |
|
CONCAT; |
|
NIL operation; PAIR}`; |
|
const storage = '"Sample"'; |
|
|
|
const nodeResult = await TezosNodeWriter.sendContractOriginationOperation(tezosNode, signer, keyStore, amount, baker, 1000, 1000, 100000, contract, storage, TezosParameterFormat.Michelson, 54, true); |
|
const groupid = clearRPCOperationGroupHash(nodeResult['operationGroupID']); |
|
console.log(`Injected origination operation with ${groupid}`); |
|
|
|
const conseilResult = await TezosConseilClient.awaitOperationConfirmation(conseilServer, conseilServer.network, groupid, 5, networkBlockTime); |
|
console.log(`Originated contract at ${conseilResult.originated_contracts}`); |
|
console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); |
|
|
|
return conseilResult.originated_contracts; |
|
} |
|
|
|
async function invokeContract(signer: Signer, keyStore: KeyStore, address: string, amount: number, parameter: string, entrypoint: string = '') { |
|
console.log(`~~ invokeContract`); |
|
|
|
let storageResult = await TezosNodeReader.getContractStorage(tezosNode, address); |
|
console.log(`initial storage: ${JSON.stringify(storageResult)}`); |
|
|
|
const { gas, storageCost: freight, estimatedFee, } = await TezosNodeWriter.testContractInvocationOperation(tezosNode, 'main', keyStore, address, amount, 0, 1000, 100000, entrypoint, parameter, TezosParameterFormat.Michelson); |
|
|
|
const nodeResult = await TezosNodeWriter.sendContractInvocationOperation(tezosNode, signer, keyStore, address, amount, estimatedFee, freight, gas, entrypoint, parameter, TezosParameterFormat.Michelson); |
|
|
|
const groupid = clearRPCOperationGroupHash(nodeResult.operationGroupID); |
|
console.log(`Injected transaction(invocation) operation with ${groupid}`); |
|
|
|
const conseilResult = await TezosConseilClient.awaitOperationConfirmation(conseilServer, conseilServer.network, groupid, 5, networkBlockTime); |
|
console.log(`Completed invocation of ${conseilResult.destination}`); |
|
storageResult = await TezosNodeReader.getContractStorage(tezosNode, address); |
|
console.log(`modified storage: ${JSON.stringify(storageResult)}`); |
|
console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); |
|
} |
|
|
|
async function parseContract(address: string) { |
|
const entryPoints = await TezosContractIntrospector.generateEntryPointsFromAddress(conseilServer, conseilServer.network, address); |
|
for (const entryPoint of entryPoints) { |
|
console.log(`${entryPoint.name}(${entryPoint.parameters.map(p => (p.name ? p.name + ': ' : '') + p.type + (p.optional ? '?' : '')).join(', ')})`) |
|
console.log(entryPoint.structure) |
|
} |
|
} |
|
|
|
async function dumpMempool(account: string) { |
|
const rr = await TezosNodeReader.getMempoolOperationsForAccount(tezosNode, account); |
|
|
|
await Promise.all( |
|
rr.map(async (r) => { |
|
const ttl = await TezosNodeReader.estimateBranchTimeout(tezosNode, r['branch']); |
|
const t = r['contents'][0]; |
|
console.log(`operation ${r['hash']} for ${new BigNumber(t.amount || 0).toNumber()}xtz expires in ${ttl} blocks`) |
|
}) |
|
); |
|
} |
|
|
|
async function run() { |
|
initConseil() |
|
|
|
// Account initialization |
|
const keyStore = await initAccount(); |
|
const signer = await SoftSigner.createSigner(TezosMessageUtils.writeKeyWithHint(keyStore.secretKey, 'edsk')); |
|
await activateAccount(signer, keyStore); |
|
await revealAccount(signer, keyStore); |
|
|
|
// Basic operations |
|
const baker = 'tz1VpvtSaSxKvykrqajFJTZqCXgoVJ5cKaM1'; // random baker from https://arronax.io/tezos/edonet/blocks |
|
const recipient = 'tz1aWXP237BLwNHJcCD4b3DutCevhqq2T1Z9' // random account from https://arronax.io/tezos/edonet/accounts |
|
await sendTransaction(signer, keyStore, recipient, 500_000); |
|
await delegateAccount(signer, keyStore, baker); |
|
|
|
// Basic contract operations |
|
// const contractAddress = await deployMichelineContract(signer, keyStore, 0, undefined); |
|
const contractAddress = await deployMichelsonContract(signer, keyStore, 0, undefined); |
|
await invokeContract(signer, keyStore, contractAddress, 0, '"new text"'); |
|
|
|
await parseContract(contractAddress); |
|
await dumpMempool(keyStore.publicKeyHash); |
|
} |
|
|
|
run(); |
async function createAccount() {
const mnemonic = conseiljs.TezosWalletUtil.generateMnemonic();
console.log(
mnemonic: ${mnemonic}
);const keystore = await conseiljs.TezosWalletUtil.unlockIdentityWithMnemonic(mnemonic, '');
console.log(
account id: ${keystore.publicKeyHash}
);console.log(
public key: ${keystore.publicKey}
);console.log(
secret key: ${keystore.privateKey}
);}
how to activate a new empty account, what is the activate code?