Skip to content

Commit

Permalink
Merge d8f2308 into e280b3e
Browse files Browse the repository at this point in the history
  • Loading branch information
anonymoussprocket committed Dec 11, 2020
2 parents e280b3e + d8f2308 commit b07093c
Show file tree
Hide file tree
Showing 16 changed files with 1,148 additions and 108 deletions.
26 changes: 26 additions & 0 deletions integration_test/chain/tezos/TezosNodeReader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,30 @@ describe('TezosNodeReader integration test suite', () => {

expect(result.header.level).to.be.greaterThan(1);
});

it('Gets delegate for a delegated implicit account', async () => {
const result = await TezosNodeReader.getDelegate(tezosServer, "tz1PnUd6R31MnjEE8VhfZhZdbGc1hrWQvjnK");
expect(result).to.not.be.undefined
});

it('Gets delegate for a delegated smart contract', async () => {
const result = await TezosNodeReader.getDelegate(tezosServer, "KT1DRJPyaDTgeXrM2cgQdp5siNF8PP5RLS7T");
expect(result).to.not.be.undefined
});

it('Gets delegate for a baker as itself', async () => {
const baker = "tz1Na5QB98cDA3BC1SQU4w3iiWGVGktU14LE"
const result = await TezosNodeReader.getDelegate(tezosServer, baker);
expect(result).to.be.equal(baker)
});

it('Returns undefined for undelegated implicit account', async () => {
const result = await TezosNodeReader.getDelegate(tezosServer, "tz1fzHtv2UqtXzFUBHuBPh2xXVv5Pv5MTh5Z");
expect(result).to.be.undefined
});

it('Returns undefined for undelegated smart contract', async () => {
const result = await TezosNodeReader.getDelegate(tezosServer, "KT1BipUDR93YFCJjVpghzVFS8N45Lkgigfqs");
expect(result).to.be.undefined
});
});
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "conseiljs",
"version": "5.0.5",
"version": "5.0.6",
"description": "Client-side library for Tezos dApp development.",
"browser": "dist/index-web.js",
"main": "dist/index.js",
Expand Down
44 changes: 44 additions & 0 deletions src/chain/tezos/TezosMessageUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,4 +552,48 @@ export namespace TezosMessageUtils {

return n.toJSNumber();
}

/**
* Calculate the address of a contract that was originated.
*
* @param operationHash The operation group hash.
* @param index The index of the origination operation in the operation group.
*/
export function calculateContractAddress(operationHash: string, index: number): string {
// Decode and slice two byte prefix off operation hash.
const decoded: Uint8Array = base58check.decode(operationHash).slice(2)

// Merge the decoded buffer with the operation prefix.
let decodedAndOperationPrefix: Array<number> = []
for (let i = 0; i < decoded.length; i++) {
decodedAndOperationPrefix.push(decoded[i])
}
decodedAndOperationPrefix = decodedAndOperationPrefix.concat([
(index & 0xff000000) >> 24,
(index & 0x00ff0000) >> 16,
(index & 0x0000ff00) >> 8,
index & 0x000000ff,
])

// Hash and encode.
const hash = blakejs.blake2b(new Uint8Array(decodedAndOperationPrefix), null, 20)
const smartContractAddressPrefix = new Uint8Array([2, 90, 121]) // KT1
const prefixedBytes = mergeBytes(smartContractAddressPrefix, hash)
return base58check.encode(prefixedBytes)
}

/**
* Helper to merge two Uint8Arrays.
*
* @param a The first array.
* @param b The second array.
* @returns A new array that contains b appended to the end of a.
*/
function mergeBytes(a: Uint8Array, b: Uint8Array): Uint8Array {
const merged = new Uint8Array(a.length + b.length)
merged.set(a)
merged.set(b, a.length)

return merged
}
}
22 changes: 17 additions & 5 deletions src/chain/tezos/TezosNodeReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ export namespace TezosNodeReader {
});
}

/**
* Gets the delegate for a smart contract or an implicit account.
*
* @param {string} server Tezos node to query
* @param {string} accountHash The smart contract address or implicit account to query.
* @returns The address of the delegate, or undefined if there was no delegate set.
*/
export async function getDelegate(server: string, accountHash: string): Promise<string | undefined> {
const contractData = await getAccountForBlock(server, 'head', accountHash)
return (contractData.delegate as unknown) as string
}

/**
* Gets a block for a given hash.
*
Expand All @@ -46,7 +58,7 @@ export namespace TezosNodeReader {
* @returns {Promise<TezosRPCTypes.TezosBlock>} Block
*/
export function getBlock(server: string, hash: string = 'head', chainid: string = 'main'): Promise<TezosRPCTypes.TezosBlock> {
return performGetRequest(server, `chains/${chainid}/blocks/${hash}`).then(json => { return <TezosRPCTypes.TezosBlock> json });
return performGetRequest(server, `chains/${chainid}/blocks/${hash}`).then(json => { return <TezosRPCTypes.TezosBlock>json });
}

/**
Expand All @@ -70,7 +82,7 @@ export namespace TezosNodeReader {
if (offset <= 0) { return getBlock(server); }

const head = await getBlock(server);
return performGetRequest(server, `chains/${chainid}/blocks/${Number(head['header']['level']) - offset}`).then(json => { return <TezosRPCTypes.TezosBlock> json });
return performGetRequest(server, `chains/${chainid}/blocks/${Number(head['header']['level']) - offset}`).then(json => { return <TezosRPCTypes.TezosBlock>json });
}

/**
Expand All @@ -84,7 +96,7 @@ export namespace TezosNodeReader {
*/
export function getAccountForBlock(server: string, blockHash: string, accountHash: string, chainid: string = 'main'): Promise<TezosRPCTypes.Contract> {
return performGetRequest(server, `chains/${chainid}/blocks/${blockHash}/context/contracts/${accountHash}`)
.then(json => <TezosRPCTypes.Contract> json);
.then(json => <TezosRPCTypes.Contract>json);
}

/**
Expand All @@ -111,7 +123,7 @@ export namespace TezosNodeReader {
*/
export async function getSpendableBalanceForAccount(server: string, accountHash: string, chainid: string = 'main'): Promise<number> {
const account = await performGetRequest(server, `chains/${chainid}/blocks/head/context/contracts/${accountHash}`) // TODO: get /balance
.then(json => <TezosRPCTypes.Contract> json);
.then(json => <TezosRPCTypes.Contract>json);
return parseInt(account.balance.toString(), 10);
}

Expand All @@ -130,7 +142,7 @@ export namespace TezosNodeReader {
}

/**
* Indicates whether an account is implicit and empty. If true, transaction will burn 0.257tz.
* Indicates whether an account is implicit and empty. If true, transaction will burn 0.06425tz.
*
* @param {string} server Tezos node to connect to
* @param {string} accountHash Account address
Expand Down
52 changes: 34 additions & 18 deletions src/chain/tezos/TezosNodeWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,10 @@ export namespace TezosNodeWriter {
*/
// TODO: move to an appropriate place
export function forgeOperations(branch: string, operations: TezosP2PMessageTypes.Operation[]): string {
log.debug('TezosNodeWriter.forgeOperations:');
log.debug(JSON.stringify(operations));
log.debug(`TezosNodeWriter.forgeOperations: ${JSON.stringify(operations)}`);
let encoded = TezosMessageUtils.writeBranch(branch);
operations.forEach(m => encoded += TezosMessageCodec.encodeOperation(m));

log.debug(`TezosNodeWriter.forgeOperations: ${encoded}`);
return encoded;
}

Expand Down Expand Up @@ -649,12 +648,8 @@ export namespace TezosNodeWriter {
storageCost: resources.storageCost + fixedOriginationStorageCost
}
}

/**
* Dry run the given operation and return consumed resources.
*
* Note: Estimating an operation on an unrevealed account is not supported and will fail. Remember to prepend
* the Reveal operation if required.
* Dry run the given operation
*
* @param {string} server Tezos node to connect to
* @param {string} chainid The chain ID to apply the operation on.
Expand All @@ -666,16 +661,7 @@ export namespace TezosNodeWriter {
chainid: string,
...operations: TezosP2PMessageTypes.Operation[]
): Promise<{ gas: number, storageCost: number }> {
const fake_signature = 'edsigu6xFLH2NpJ1VcYshpjW99Yc1TAL1m2XBqJyXrxcZQgBMo8sszw2zm626yjpA3pWMhjpsahLrWdmvX9cqhd4ZEUchuBuFYy';
const fake_chainid = 'NetXdQprcVkpaWU';
const fake_branch = 'BL94i2ShahPx3BoNs6tJdXDdGeoJ9ukwujUA2P8WJwULYNdimmq';

const response = await performPostRequest(server, `chains/${chainid}/blocks/head/helpers/scripts/run_operation`, { chain_id: fake_chainid, operation: { branch: fake_branch, contents: operations, signature: fake_signature } });
const responseText = await response.text();

parseRPCError(responseText);

const responseJSON = JSON.parse(responseText);
const responseJSON = dryRunOperation(server, chainid, ...operations);

let gas = 0;
let storageCost = 0;
Expand All @@ -701,6 +687,36 @@ export namespace TezosNodeWriter {
return { gas, storageCost };
}

/**
* Dry run the given operation and return consumed resources.
*
* Note: Estimating an operation on an unrevealed account is not supported and will fail. Remember to prepend
* the Reveal operation if required.
* @param {string} server Tezos node to connect to
* @param {string} chainid The chain ID to apply the operation on.
* @param {TezosP2PMessageTypes.Operation} operations A set of operations to update.
* @returns {Promise<object>} JSON-encoded response
*/
export async function dryRunOperation(
server: string,
chainid: string,
...operations: TezosP2PMessageTypes.Operation[]
): Promise<Response> {
const fake_signature = 'edsigu6xFLH2NpJ1VcYshpjW99Yc1TAL1m2XBqJyXrxcZQgBMo8sszw2zm626yjpA3pWMhjpsahLrWdmvX9cqhd4ZEUchuBuFYy';
const fake_chainid = 'NetXdQprcVkpaWU';
const fake_branch = 'BL94i2ShahPx3BoNs6tJdXDdGeoJ9ukwujUA2P8WJwULYNdimmq';

const response = await performPostRequest(server, `chains/${chainid}/blocks/head/helpers/scripts/run_operation`, { chain_id: fake_chainid, operation: { branch: fake_branch, contents: operations, signature: fake_signature } });
const responseText = await response.text();

parseRPCError(responseText);

const responseJSON = JSON.parse(responseText);

return responseJSON;
}

/**
* This function checks if the server response contains an error. There are multiple formats for errors coming
* back from the server, this method attempts to normalized them for downstream parsing.
Expand Down

0 comments on commit b07093c

Please sign in to comment.