Skip to content

Commit 8146def

Browse files
authored
Merge pull request #326 from Cryptonomic/release/505
Release 5.0.6
2 parents e280b3e + fd4ce0e commit 8146def

20 files changed

Lines changed: 1218 additions & 122 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ TBD
5959
<html>
6060
<head>
6161
<script src="https://cdn.jsdelivr.net/gh/cryptonomic/conseiljs/dist-web/conseiljs.min.js"
62-
integrity="sha384-DsZ98An5RJlEquKpG7VziukP7Zqae8IlsF9VmTnz41Ga8FvAx6Hvn0hMkpBj3pms"
62+
integrity="sha384-Y4koW2PhHK4PfHtil6LTWRqMxy3k3ym8AWecTAIuA0cLcJNGFdLmrG2/FXZucfZp"
6363
crossorigin="anonymous"></script>
6464
<script src="https://cdn.jsdelivr.net/gh/cryptonomic/conseiljs-softsigner/dist-web/conseiljs-softsigner.min.js"
6565
integrity="sha384-V1iaajn0x/SMFcZ9Y/xNQmqQSKyll6Dzt27U6OWiv8NdbHTVaHOGHdQ8g0G68HPd"

dist-web/conseiljs.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Unlike the nodejs sample, it's not possible to configure fetch or logger referen
5252
<html>
5353
<head>
5454
<script src="https://cdn.jsdelivr.net/gh/cryptonomic/conseiljs/dist-web/conseiljs.min.js"
55-
integrity="sha384-DsZ98An5RJlEquKpG7VziukP7Zqae8IlsF9VmTnz41Ga8FvAx6Hvn0hMkpBj3pms"
55+
integrity="sha384-Y4koW2PhHK4PfHtil6LTWRqMxy3k3ym8AWecTAIuA0cLcJNGFdLmrG2/FXZucfZp"
5656
crossorigin="anonymous"></script>
5757
<script src="https://cdn.jsdelivr.net/gh/cryptonomic/conseiljs-softsigner/dist-web/conseiljs-softsigner.min.js"
5858
crossorigin="anonymous"></script>

integration_test/chain/tezos/TezosNodeReader.spec.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,30 @@ describe('TezosNodeReader integration test suite', () => {
6060

6161
expect(result.header.level).to.be.greaterThan(1);
6262
});
63+
64+
it('Gets delegate for a delegated implicit account', async () => {
65+
const result = await TezosNodeReader.getDelegate(tezosServer, "tz1PnUd6R31MnjEE8VhfZhZdbGc1hrWQvjnK");
66+
expect(result).to.not.be.undefined
67+
});
68+
69+
it('Gets delegate for a delegated smart contract', async () => {
70+
const result = await TezosNodeReader.getDelegate(tezosServer, "KT1DRJPyaDTgeXrM2cgQdp5siNF8PP5RLS7T");
71+
expect(result).to.not.be.undefined
72+
});
73+
74+
it('Gets delegate for a baker as itself', async () => {
75+
const baker = "tz1Na5QB98cDA3BC1SQU4w3iiWGVGktU14LE"
76+
const result = await TezosNodeReader.getDelegate(tezosServer, baker);
77+
expect(result).to.be.equal(baker)
78+
});
79+
80+
it('Returns undefined for undelegated implicit account', async () => {
81+
const result = await TezosNodeReader.getDelegate(tezosServer, "tz1fzHtv2UqtXzFUBHuBPh2xXVv5Pv5MTh5Z");
82+
expect(result).to.be.undefined
83+
});
84+
85+
it('Returns undefined for undelegated smart contract', async () => {
86+
const result = await TezosNodeReader.getDelegate(tezosServer, "KT1BipUDR93YFCJjVpghzVFS8N45Lkgigfqs");
87+
expect(result).to.be.undefined
88+
});
6389
});

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "conseiljs",
3-
"version": "5.0.5",
3+
"version": "5.0.6",
44
"description": "Client-side library for Tezos dApp development.",
55
"browser": "dist/index-web.js",
66
"main": "dist/index.js",

src/chain/tezos/TezosMessageUtil.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,4 +552,48 @@ export namespace TezosMessageUtils {
552552

553553
return n.toJSNumber();
554554
}
555+
556+
/**
557+
* Calculate the address of a contract that was originated.
558+
*
559+
* @param operationHash The operation group hash.
560+
* @param index The index of the origination operation in the operation group.
561+
*/
562+
export function calculateContractAddress(operationHash: string, index: number): string {
563+
// Decode and slice two byte prefix off operation hash.
564+
const decoded: Uint8Array = base58check.decode(operationHash).slice(2)
565+
566+
// Merge the decoded buffer with the operation prefix.
567+
let decodedAndOperationPrefix: Array<number> = []
568+
for (let i = 0; i < decoded.length; i++) {
569+
decodedAndOperationPrefix.push(decoded[i])
570+
}
571+
decodedAndOperationPrefix = decodedAndOperationPrefix.concat([
572+
(index & 0xff000000) >> 24,
573+
(index & 0x00ff0000) >> 16,
574+
(index & 0x0000ff00) >> 8,
575+
index & 0x000000ff,
576+
])
577+
578+
// Hash and encode.
579+
const hash = blakejs.blake2b(new Uint8Array(decodedAndOperationPrefix), null, 20)
580+
const smartContractAddressPrefix = new Uint8Array([2, 90, 121]) // KT1
581+
const prefixedBytes = mergeBytes(smartContractAddressPrefix, hash)
582+
return base58check.encode(prefixedBytes)
583+
}
584+
585+
/**
586+
* Helper to merge two Uint8Arrays.
587+
*
588+
* @param a The first array.
589+
* @param b The second array.
590+
* @returns A new array that contains b appended to the end of a.
591+
*/
592+
function mergeBytes(a: Uint8Array, b: Uint8Array): Uint8Array {
593+
const merged = new Uint8Array(a.length + b.length)
594+
merged.set(a)
595+
merged.set(b, a.length)
596+
597+
return merged
598+
}
555599
}

src/chain/tezos/TezosNodeReader.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ export namespace TezosNodeReader {
3737
});
3838
}
3939

40+
/**
41+
* Gets the delegate for a smart contract or an implicit account.
42+
*
43+
* @param {string} server Tezos node to query
44+
* @param {string} accountHash The smart contract address or implicit account to query.
45+
* @returns The address of the delegate, or undefined if there was no delegate set.
46+
*/
47+
export async function getDelegate(server: string, accountHash: string): Promise<string | undefined> {
48+
const contractData = await getAccountForBlock(server, 'head', accountHash)
49+
return contractData.delegate;
50+
}
51+
4052
/**
4153
* Gets a block for a given hash.
4254
*
@@ -46,7 +58,7 @@ export namespace TezosNodeReader {
4658
* @returns {Promise<TezosRPCTypes.TezosBlock>} Block
4759
*/
4860
export function getBlock(server: string, hash: string = 'head', chainid: string = 'main'): Promise<TezosRPCTypes.TezosBlock> {
49-
return performGetRequest(server, `chains/${chainid}/blocks/${hash}`).then(json => { return <TezosRPCTypes.TezosBlock> json });
61+
return performGetRequest(server, `chains/${chainid}/blocks/${hash}`).then(json => { return <TezosRPCTypes.TezosBlock>json });
5062
}
5163

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

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

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

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

@@ -130,7 +142,7 @@ export namespace TezosNodeReader {
130142
}
131143

132144
/**
133-
* Indicates whether an account is implicit and empty. If true, transaction will burn 0.257tz.
145+
* Indicates whether an account is implicit and empty. If true, transaction will burn 0.06425tz.
134146
*
135147
* @param {string} server Tezos node to connect to
136148
* @param {string} accountHash Account address

src/chain/tezos/TezosNodeWriter.ts

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,10 @@ export namespace TezosNodeWriter {
5050
*/
5151
// TODO: move to an appropriate place
5252
export function forgeOperations(branch: string, operations: TezosP2PMessageTypes.Operation[]): string {
53-
log.debug('TezosNodeWriter.forgeOperations:');
54-
log.debug(JSON.stringify(operations));
53+
log.debug(`TezosNodeWriter.forgeOperations: ${JSON.stringify(operations)}`);
5554
let encoded = TezosMessageUtils.writeBranch(branch);
5655
operations.forEach(m => encoded += TezosMessageCodec.encodeOperation(m));
57-
56+
log.debug(`TezosNodeWriter.forgeOperations: ${encoded}`);
5857
return encoded;
5958
}
6059

@@ -171,14 +170,16 @@ export namespace TezosNodeWriter {
171170
*/
172171
export async function sendOperation(server: string, operations: TezosP2PMessageTypes.Operation[], signer: Signer, offset: number = 54): Promise<TezosTypes.OperationResult> {
173172
const blockHead = await TezosNodeReader.getBlockAtOffset(server, offset);
174-
const forgedOperationGroup = forgeOperations(blockHead.hash, operations);
173+
const blockHash = blockHead.hash.slice(0, 51); // consider throwing an error instead
174+
175+
const forgedOperationGroup = forgeOperations(blockHash, operations);
175176

176177
const opSignature = await signer.signOperation(Buffer.from(TezosConstants.OperationGroupWatermark + forgedOperationGroup, 'hex'));
177178

178179
const signedOpGroup = Buffer.concat([Buffer.from(forgedOperationGroup, 'hex'), opSignature]);
179180
const base58signature = TezosMessageUtils.readSignatureWithHint(opSignature, signer.getSignerCurve());
180181
const opPair = { bytes: signedOpGroup, signature: base58signature };
181-
const appliedOp = await preapplyOperation(server, blockHead.hash, blockHead.protocol, operations, opPair);
182+
const appliedOp = await preapplyOperation(server, blockHash, blockHead.protocol, operations, opPair);
182183
const injectedOperation = await injectOperation(server, opPair);
183184

184185
return { results: appliedOp[0], operationGroupID: injectedOperation }; // TODO
@@ -649,12 +650,8 @@ export namespace TezosNodeWriter {
649650
storageCost: resources.storageCost + fixedOriginationStorageCost
650651
}
651652
}
652-
653653
/**
654-
* Dry run the given operation and return consumed resources.
655-
*
656-
* Note: Estimating an operation on an unrevealed account is not supported and will fail. Remember to prepend
657-
* the Reveal operation if required.
654+
* Dry run the given operation
658655
*
659656
* @param {string} server Tezos node to connect to
660657
* @param {string} chainid The chain ID to apply the operation on.
@@ -666,16 +663,7 @@ export namespace TezosNodeWriter {
666663
chainid: string,
667664
...operations: TezosP2PMessageTypes.Operation[]
668665
): Promise<{ gas: number, storageCost: number }> {
669-
const fake_signature = 'edsigu6xFLH2NpJ1VcYshpjW99Yc1TAL1m2XBqJyXrxcZQgBMo8sszw2zm626yjpA3pWMhjpsahLrWdmvX9cqhd4ZEUchuBuFYy';
670-
const fake_chainid = 'NetXdQprcVkpaWU';
671-
const fake_branch = 'BL94i2ShahPx3BoNs6tJdXDdGeoJ9ukwujUA2P8WJwULYNdimmq';
672-
673-
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 } });
674-
const responseText = await response.text();
675-
676-
parseRPCError(responseText);
677-
678-
const responseJSON = JSON.parse(responseText);
666+
const responseJSON = dryRunOperation(server, chainid, ...operations);
679667

680668
let gas = 0;
681669
let storageCost = 0;
@@ -701,6 +689,36 @@ export namespace TezosNodeWriter {
701689
return { gas, storageCost };
702690
}
703691

692+
/**
693+
* Dry run the given operation and return consumed resources.
694+
*
695+
* Note: Estimating an operation on an unrevealed account is not supported and will fail. Remember to prepend
696+
* the Reveal operation if required.
697+
698+
* @param {string} server Tezos node to connect to
699+
* @param {string} chainid The chain ID to apply the operation on.
700+
* @param {TezosP2PMessageTypes.Operation} operations A set of operations to update.
701+
* @returns {Promise<object>} JSON-encoded response
702+
*/
703+
export async function dryRunOperation(
704+
server: string,
705+
chainid: string,
706+
...operations: TezosP2PMessageTypes.Operation[]
707+
): Promise<Response> {
708+
const fake_signature = 'edsigu6xFLH2NpJ1VcYshpjW99Yc1TAL1m2XBqJyXrxcZQgBMo8sszw2zm626yjpA3pWMhjpsahLrWdmvX9cqhd4ZEUchuBuFYy';
709+
const fake_chainid = 'NetXdQprcVkpaWU';
710+
const fake_branch = 'BL94i2ShahPx3BoNs6tJdXDdGeoJ9ukwujUA2P8WJwULYNdimmq';
711+
712+
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 } });
713+
const responseText = await response.text();
714+
715+
parseRPCError(responseText);
716+
717+
const responseJSON = JSON.parse(responseText);
718+
719+
return responseJSON;
720+
}
721+
704722
/**
705723
* This function checks if the server response contains an error. There are multiple formats for errors coming
706724
* back from the server, this method attempts to normalized them for downstream parsing.

0 commit comments

Comments
 (0)