From 7bb318d023459ba604ec7b2203a45976ba6793d5 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Wed, 30 Sep 2020 00:36:43 -0400 Subject: [PATCH 01/33] - dump encoded messages to debug log --- src/chain/tezos/TezosNodeWriter.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/chain/tezos/TezosNodeWriter.ts b/src/chain/tezos/TezosNodeWriter.ts index 872681e1..17751441 100644 --- a/src/chain/tezos/TezosNodeWriter.ts +++ b/src/chain/tezos/TezosNodeWriter.ts @@ -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; } From 232ba95fc14ea6321a4ed1029160944bb7b51f57 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Tue, 20 Oct 2020 21:19:01 -0400 Subject: [PATCH 02/33] - initial dexter pool conract support --- src/chain/tezos/contracts/DexterPoolHelper.ts | 205 ++++++++++++++++++ .../tezos/contracts/DexterTokenHelper.ts | 75 ------- src/index-web.ts | 2 +- src/index.ts | 2 +- 4 files changed, 207 insertions(+), 77 deletions(-) create mode 100644 src/chain/tezos/contracts/DexterPoolHelper.ts delete mode 100644 src/chain/tezos/contracts/DexterTokenHelper.ts diff --git a/src/chain/tezos/contracts/DexterPoolHelper.ts b/src/chain/tezos/contracts/DexterPoolHelper.ts new file mode 100644 index 00000000..d878f1c8 --- /dev/null +++ b/src/chain/tezos/contracts/DexterPoolHelper.ts @@ -0,0 +1,205 @@ +import bigInt from 'big-integer'; +import { JSONPath } from 'jsonpath-plus'; + +import { KeyStore, Signer } from '../../../types/ExternalInterfaces'; +import * as TezosTypes from '../../../types/tezos/TezosChainTypes'; +import { TezosNodeReader } from '../TezosNodeReader'; +import { TezosNodeWriter } from '../TezosNodeWriter'; +import { TezosContractUtils } from './TezosContractUtils'; +import { TezosMessageUtils } from '../TezosMessageUtil'; + +interface DexterPoolSimpleStorage { + balanceMap: number; + administrator: string; + token: string; + tokenBalance: number; + xtzBalance: number; + selfIsUpdatingTokenPool: boolean; + freeze_baker: boolean; + lqt_total: number; +} + +/** + * mainnet KT1DrJV8vhkdLEj76h1H9Q4irZDqAkMPo1Qf tzbtc + * mainner KT1Puc9St8wdNoGtLiD2WXaHbWU7styaxYhD usdtz + * + * https://gitlab.com/camlcase-dev/dexter-integration + */ +export namespace DexterPoolHelper { + const DexterPoolLiquidityOperationGasLimit = 500_000; + const DexterPoolLiquidityOperationStorageLimit = 5_000; + const DexterPoolExchangeOperationGasLimit = 500_000; + const DexterPoolExchangeOperationStorageLimit = 5_000; + const ExchangeMultiplier = 997; + + /** + * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. + * + * @param server Destination Tezos node. + * @param address Contract address to query. + */ + export async function verifyDestination(server: string, address: string): Promise { + return TezosContractUtils.verifyDestination(server, address, 'a72954311c48dcc28279590d82870611'); + } + + /** + * In contrast to verifyDestination, this function uses compares Michelson hashes. + * + * @param script + */ + export function verifyScript(script: string): boolean { + return TezosContractUtils.verifyScript(script, 'yyy'); + } + + export async function getSimpleStorage(server: string, address: string): Promise { + const storageResult = await TezosNodeReader.getContractStorage(server, address); + + return { + balanceMap: Number(JSONPath({ path: '$.args[0].int', json: storageResult })[0]), + administrator: JSONPath({ path: '$.args[1].args[1].args[0].args[0].string', json: storageResult })[0], + token: JSONPath({ path: '$.args[1].args[1].args[0].args[1].string', json: storageResult })[0], + tokenBalance: Number(JSONPath({ path: '$.args[1].args[1].args[1].args[1].int', json: storageResult })[0]), + xtzBalance: Number(JSONPath({ path: '$.args[1].args[1].args[1].args[0].int', json: storageResult })[0]), + selfIsUpdatingTokenPool: (JSONPath({ path: '$.args[1].args[0].args[0].prim', json: storageResult })[0]).toString().toLowerCase().startsWith('t'), + freeze_baker: (JSONPath({ path: '$.args[1].args[0].args[1].args[0].prim', json: storageResult })[0]).toString().toLowerCase().startsWith('t'), + lqt_total: Number(JSONPath({ path: '$.args[1].args[0].args[1].args[1].int', json: storageResult })[0]) + }; + } + + export async function getAccountBalance(server: string, mapid: number, account: string): Promise { + try { + const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData(account, 'address'), 'hex')); + const mapResult = await TezosNodeReader.getValueForBigMapKey(server, mapid, packedKey); + + if (mapResult === undefined) { throw new Error(`Map ${mapid} does not contain a record for ${account}`); } + + const jsonresult = JSONPath({ path: '$.args[0].int', json: mapResult }); + return Number(jsonresult[0]); + } catch { + return 0; + } + } + + export async function getAccountAllowance(server: string, mapid: number, account: string, spender: string) { + const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData(account, 'address'), 'hex')); + const mapResult = await TezosNodeReader.getValueForBigMapKey(server, mapid, packedKey); + + if (mapResult === undefined) { throw new Error(`Map ${mapid} does not contain a record for ${account}/${spender}`); } + + let allowances = new Map(); + JSONPath({ path: '$.args[1][*].args', json: mapResult }).forEach(v => allowances[v[0]['string']] = Number(v[1]['int'])); + + return allowances[spender] || 0; + } + + export async function addLiquidity(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, xtzAmount: number, liquidityAmount: number, tokenAmount: number, expiration: Date): Promise { + //(pair (address :owner) (nat :minLqtMinted)) (pair (nat :maxTokensDeposited) (timestamp :deadline))) + const parameters = `(Pair (Pair "${keyStore.publicKeyHash}" ${liquidityAmount}) (Pair ${tokenAmount} "${expiration.toISOString()}"))`; + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation(server, signer, keyStore, contract, xtzAmount, fee, DexterPoolLiquidityOperationStorageLimit, DexterPoolLiquidityOperationGasLimit, 'addLiquidity', parameters, TezosTypes.TezosParameterFormat.Michelson); + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } + + export async function removeLiquidity(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, balance: number, xtzBalance: number, tokenBalance: number, expiration: Date): Promise { + //(pair (address :owner) (pair (address :to) (nat :lqtBurned))) (pair (mutez :minXtzWithdrawn) (pair (nat :minTokensWithdrawn) (timestamp :deadline))) + const parameters = `(Pair (Pair "${keyStore.publicKeyHash}" (Pair "${keyStore.publicKeyHash}" ${balance})) (Pair ${xtzBalance} (Pair ${tokenBalance} "${expiration.toISOString()}")))`; + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation(server, signer, keyStore, contract, 0, fee, DexterPoolLiquidityOperationStorageLimit, DexterPoolLiquidityOperationGasLimit, 'removeLiquidity', parameters, TezosTypes.TezosParameterFormat.Michelson); + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } + + export async function xtzToToken(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, xtzAmount: number, tokenAmount: number, expiration: Date): Promise { + //(pair %xtzToToken (address :to) (pair (nat :minTokensBought) (timestamp :deadline))) + const parameters = `(Pair "${keyStore.publicKeyHash}" (Pair ${tokenAmount} "${expiration.toISOString()}"))`; + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation(server, signer, keyStore, contract, xtzAmount, fee, DexterPoolExchangeOperationStorageLimit, DexterPoolExchangeOperationGasLimit, 'xtzToToken', parameters, TezosTypes.TezosParameterFormat.Michelson); + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } + + export async function tokenToXtz(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, xtzAmount: number, tokenAmount: number, expiration: Date): Promise { + //(pair %tokenToXtz (pair (address :owner) (address :to)) (pair (nat :tokensSold) (pair (mutez :minXtzBought) (timestamp :deadline)))) + const parameters = `(Pair (Pair "${keyStore.publicKeyHash}" "${keyStore.publicKeyHash}") (Pair ${tokenAmount} (Pair ${xtzAmount} "${expiration.toISOString()}")))`; + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation(server, signer, keyStore, contract, 0, fee, DexterPoolExchangeOperationStorageLimit, DexterPoolExchangeOperationGasLimit, 'tokenToXtz', parameters, TezosTypes.TezosParameterFormat.Michelson); + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } + + export async function tokenToToken(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, otherPoolContract: string, sellAmount: number, buyAmount: number, expiration: Date): Promise { + //(pair %tokenToToken (pair (address :outputDexterContract) (pair (nat :minTokensBought) (address :owner))) (pair (address :to) (pair (nat :tokensSold) (timestamp :deadline)))) + const parameters = `(Pair (Pair "${otherPoolContract}" (Pair ${buyAmount} "${keyStore.publicKeyHash}")) (Pair "${keyStore.publicKeyHash}" (Pair ${sellAmount} "${expiration.toISOString()}")))`; + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation(server, signer, keyStore, contract, 0, fee, DexterPoolExchangeOperationStorageLimit, 1_000_000, 'tokenToToken', parameters, TezosTypes.TezosParameterFormat.Michelson); + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } + + export async function approve(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, spender: string, newAllowance: number, currentAllowance: number): Promise { + //(pair %approve (address :spender) (pair (nat :allowance) (nat :currentAllowance))) + const parameters = `(Pair "${spender}" (Pair ${newAllowance} ${currentAllowance}))`; + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation(server, signer, keyStore, contract, 0, fee, DexterPoolExchangeOperationStorageLimit, DexterPoolExchangeOperationGasLimit, 'approve', parameters, TezosTypes.TezosParameterFormat.Michelson); + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } + + /** + * Show pending applied operations against this contract in the mempool + */ + export async function previewTransactions() { + // + } + + /** + * + * @param xtzDeposit XTZ amount of the proposed transaction + * @param tokenBalance Pool token balance + * @param xtzBalance Pool XTZ balance + * @returns Token amount required for the matching XTZ balance + */ + export function calcTokenLiquidityRequirement(xtzDeposit: number, tokenBalance: number, xtzBalance: number): number { + return bigInt(xtzDeposit).multiply(bigInt(tokenBalance)).divide(bigInt(xtzBalance)).toJSNumber(); + } + + /** + * Returns the token exchange rate for a given XTZ amount. + * + * @param xtzDeposit + * @param tokenBalance + * @param xtzBalance + */ + export function getTokenExchangeRate(xtzAmount: number, tokenBalance: number, xtzBalance: number) { + const n = bigInt(xtzAmount).multiply(bigInt(tokenBalance)).multiply(bigInt(ExchangeMultiplier)); + const d = bigInt(xtzBalance).multiply(bigInt(1000)).add(bigInt(xtzAmount).multiply(bigInt(ExchangeMultiplier))) + + return n.divide(d).divide(bigInt(xtzAmount)).toJSNumber(); + } + + /** + * Returns the XTZ exchange rate for a given token amount + * + * @param tokenAmount + * @param tokenBalance + * @param xtzBalance + */ + export function getXTZExchangeRate(tokenAmount: number, tokenBalance: number, xtzBalance: number) { + const n = bigInt(tokenAmount).multiply(bigInt(xtzBalance)).multiply(bigInt(ExchangeMultiplier)); + const d = bigInt(tokenBalance).multiply(bigInt(1000)).add(bigInt(tokenAmount).multiply(bigInt(ExchangeMultiplier))) + + return n.divide(d).divide(bigInt(tokenAmount)).toJSNumber(); + } + + //const lqtMinted = bigInt(xtzDeposit).multiply(bigInt(poolStorage.lqt_total)).divide(bigInt(poolStorage.xtzBalance)).toJSNumber(); + + /** + * Estimates the cost of buying 1% share of the pool in terms of XTZ + */ + export function estimateShareCost(xtzBalance: number, tokenBalance: number): { xtzCost: number, tokenCost: number } { + const xtzShare = bigInt(xtzBalance).divide(bigInt(100)).toJSNumber(); + const tokenShare = calcTokenLiquidityRequirement(xtzShare, tokenBalance, xtzBalance); + + return { xtzCost: xtzShare, tokenCost: tokenShare }; + } +} diff --git a/src/chain/tezos/contracts/DexterTokenHelper.ts b/src/chain/tezos/contracts/DexterTokenHelper.ts deleted file mode 100644 index 7cc05c1f..00000000 --- a/src/chain/tezos/contracts/DexterTokenHelper.ts +++ /dev/null @@ -1,75 +0,0 @@ -import * as blakejs from 'blakejs'; -import { JSONPath } from 'jsonpath-plus'; - -import { TezosMessageUtils } from '../TezosMessageUtil'; -import { TezosNodeReader } from '../TezosNodeReader'; - -/** - * Awaiting contracts at https://gitlab.com/camlcase-dev/dexter - */ -export namespace DexterTokenHelper { - /** - * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. - * - * @param server Destination Tezos node. - * @param address Contract address to query. - */ - export async function verifyDestination(server: string, address: string): Promise { - const contract = await TezosNodeReader.getAccountForBlock(server, 'head', address); - - if (!!!contract.script) { throw new Error(`No code found at ${address}`); } - - const k = Buffer.from(blakejs.blake2s(contract['script'].toString(), null, 16)).toString('hex'); - - if (k !== '1234') { throw new Error(`Contract at ${address} does not match the expected code hash`); } - - return true; - } - - /** - * Retrieves high level storage, including map id and token supply cap. - * - * @param server Destination Tezos node. - * @param address Contract address to query. - */ - export async function getBasicStorage(server: string, address: string) { - const storageResult = await TezosNodeReader.getContractStorage(server, address); - console.log('-----') - console.log(storageResult); - console.log('-----') - - return { - mapid: Number(JSONPath({ path: '$.args[0].int', json: storageResult })[0]), - totalSupply: Number(JSONPath({ path: '$.args[1].int', json: storageResult })[0]) - }; - } - - /** - * - * - * @param server Destination Tezos node. - * @param mapid bigmap reference to query. - * @param account Account address to query. - */ - export async function getAddressRecord(server: string, mapid: number, account: string) { - const key = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData(account, 'address'), 'hex')); - const mapResult = await TezosNodeReader.getValueForBigMapKey(server, mapid, key); - - if (!!!mapResult) { return undefined; } - - return { - allowances: JSONPath({ path: '$.args[0]', json: mapResult })[0], - balance: Number(JSONPath({ path: '$.args[1].int', json: mapResult })[0]) - }; - } - - /** - * - * @param server Destination Tezos node. - * @param manager Token manager address - * @param supply Initial token supply - */ - export async function deployContract(server: string, manager: string, supply: number) { - - } -} diff --git a/src/index-web.ts b/src/index-web.ts index f370935c..2d867cab 100644 --- a/src/index-web.ts +++ b/src/index-web.ts @@ -11,7 +11,7 @@ export * from './chain/tezos/TezosNodeReader'; export * from './chain/tezos/TezosNodeWriter'; export * from './chain/tezos/contracts/BabylonDelegationHelper'; export * from './chain/tezos/contracts/CryptonomicNameServiceHelper'; -export * from './chain/tezos/contracts/DexterTokenHelper'; +export * from './chain/tezos/contracts/DexterPoolHelper'; export * from './chain/tezos/contracts/MurbardMultisigHelper'; export * from './chain/tezos/contracts/StakerDAOTokenHelper'; export * from './chain/tezos/contracts/TCFBakerRegistryHelper'; diff --git a/src/index.ts b/src/index.ts index 2fd2c535..486b98cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,7 +16,7 @@ export * from "./chain/tezos/TezosNodeReader"; export * from "./chain/tezos/TezosNodeWriter"; export * from './chain/tezos/contracts/BabylonDelegationHelper'; export * from './chain/tezos/contracts/CryptonomicNameServiceHelper'; -export * from './chain/tezos/contracts/DexterTokenHelper'; +export * from './chain/tezos/contracts/DexterPoolHelper'; export * from './chain/tezos/contracts/MurbardMultisigHelper'; export * from './chain/tezos/contracts/StakerDAOTokenHelper'; export * from './chain/tezos/contracts/TCFBakerRegistryHelper'; From 23b5f830ba8784c24bdb4da9716d7d0b9294f6b5 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Tue, 20 Oct 2020 22:30:40 -0400 Subject: [PATCH 03/33] - bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2bd31875..d6d085f1 100644 --- a/package.json +++ b/package.json @@ -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", From bcc858b93773bd2f3486b232c529a61acfbc4b15 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Mon, 9 Nov 2020 01:56:35 -0500 Subject: [PATCH 04/33] - Dexter unit tests --- src/chain/tezos/contracts/DexterPoolHelper.ts | 169 +++++++++++++++--- .../tezos/contracts/DexterPoolHelper.spec.ts | 69 +++++++ 2 files changed, 216 insertions(+), 22 deletions(-) create mode 100644 test/chain/tezos/contracts/DexterPoolHelper.spec.ts diff --git a/src/chain/tezos/contracts/DexterPoolHelper.ts b/src/chain/tezos/contracts/DexterPoolHelper.ts index d878f1c8..4152710f 100644 --- a/src/chain/tezos/contracts/DexterPoolHelper.ts +++ b/src/chain/tezos/contracts/DexterPoolHelper.ts @@ -20,10 +20,11 @@ interface DexterPoolSimpleStorage { } /** - * mainnet KT1DrJV8vhkdLEj76h1H9Q4irZDqAkMPo1Qf tzbtc - * mainner KT1Puc9St8wdNoGtLiD2WXaHbWU7styaxYhD usdtz + * Contract wrapper for http://dexter.exchange/ pool contracts, intended for use on mainnet with KT1Puc9St8wdNoGtLiD2WXaHbWU7styaxYhD (usdtz) and KT1DrJV8vhkdLEj76h1H9Q4irZDqAkMPo1Qf (tzbtc). + * + * Tested on carthagenet with KT1RtNatBzmk2AvJKm9Mx6b55GcQejJneK7t. * - * https://gitlab.com/camlcase-dev/dexter-integration + * Based on integration documentation provided at https://gitlab.com/camlcase-dev/dexter-integration. */ export namespace DexterPoolHelper { const DexterPoolLiquidityOperationGasLimit = 500_000; @@ -51,6 +52,21 @@ export namespace DexterPoolHelper { return TezosContractUtils.verifyScript(script, 'yyy'); } + /** + * Queries the tezos node directly for basic contract storage. + * + * @param server Destination Tezos node. + * @param address Contract address to query. + * @returns + * - balanceMap: bigmap index of the liquidity balance map + * - administrator: Contract administrator + * - token: Token address this pool services + * - tokenBalance: Total token balance held in the pool + * - xtzBalance: Total XTZ balance held in the pool + * - selfIsUpdatingTokenPool + * - freeze_baker + * - lqt_total Liquidity token balance + */ export async function getSimpleStorage(server: string, address: string): Promise { const storageResult = await TezosNodeReader.getContractStorage(server, address); @@ -66,6 +82,13 @@ export namespace DexterPoolHelper { }; } + /** + * Queries the Tezos node for the liquidity balance of the requested account. + * + * @param server Destination Tezos node. + * @param mapid bigmap id of the pool to query. + * @param account Account to query. + */ export async function getAccountBalance(server: string, mapid: number, account: string): Promise { try { const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData(account, 'address'), 'hex')); @@ -80,6 +103,14 @@ export namespace DexterPoolHelper { } } + /** + * Queries the Tezos node for the liquidity balance approval for a given spender on the requested account. + * + * @param server Destination Tezos node. + * @param mapid bigmap id of the pool to query. + * @param account Account to query. + * @param spender Spender to get balance for. + */ export async function getAccountAllowance(server: string, mapid: number, account: string, spender: string) { const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData(account, 'address'), 'hex')); const mapResult = await TezosNodeReader.getValueForBigMapKey(server, mapid, packedKey); @@ -92,7 +123,20 @@ export namespace DexterPoolHelper { return allowances[spender] || 0; } - export async function addLiquidity(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, xtzAmount: number, liquidityAmount: number, tokenAmount: number, expiration: Date): Promise { + /** + * Adds liquidity to the pool using the `addLiquidity` entry point of the contract pool. Deposits both XTZ and a matching token balance. + * + * @param server Destination Tezos node. + * @param signer + * @param keyStore + * @param contract + * @param fee + * @param liquidityAmount Expected liquidity amount + * @param xtzAmount + * @param tokenAmount + * @param expiration Request expiration date. + */ + export async function addLiquidity(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, liquidityAmount: number, xtzAmount: number, tokenAmount: number, expiration: Date): Promise { //(pair (address :owner) (nat :minLqtMinted)) (pair (nat :maxTokensDeposited) (timestamp :deadline))) const parameters = `(Pair (Pair "${keyStore.publicKeyHash}" ${liquidityAmount}) (Pair ${tokenAmount} "${expiration.toISOString()}"))`; @@ -101,6 +145,19 @@ export namespace DexterPoolHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + /** + * Removes liquidity from the pool using the `removeLiquidity` entry point. + * + * @param server Destination Tezos node. + * @param signer + * @param keyStore + * @param contract + * @param fee + * @param balance Liquidity amount to withdraw. + * @param xtzBalance Expected XTZ balance + * @param tokenBalance Expected token balance + * @param expiration Request expiration date. + */ export async function removeLiquidity(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, balance: number, xtzBalance: number, tokenBalance: number, expiration: Date): Promise { //(pair (address :owner) (pair (address :to) (nat :lqtBurned))) (pair (mutez :minXtzWithdrawn) (pair (nat :minTokensWithdrawn) (timestamp :deadline))) const parameters = `(Pair (Pair "${keyStore.publicKeyHash}" (Pair "${keyStore.publicKeyHash}" ${balance})) (Pair ${xtzBalance} (Pair ${tokenBalance} "${expiration.toISOString()}")))`; @@ -110,6 +167,18 @@ export namespace DexterPoolHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + /** + * + * Convert an XTZz balance into an token balance. + * @param server + * @param signer + * @param keyStore + * @param contract + * @param fee + * @param xtzAmount + * @param tokenAmount + * @param expiration Request expiration date. + */ export async function xtzToToken(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, xtzAmount: number, tokenAmount: number, expiration: Date): Promise { //(pair %xtzToToken (address :to) (pair (nat :minTokensBought) (timestamp :deadline))) const parameters = `(Pair "${keyStore.publicKeyHash}" (Pair ${tokenAmount} "${expiration.toISOString()}"))`; @@ -119,6 +188,18 @@ export namespace DexterPoolHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + /** + * Convert a token balance into an XTZ balance. + * + * @param server Destination Tezos node. + * @param signer + * @param keyStore + * @param contract + * @param fee + * @param xtzAmount + * @param tokenAmount + * @param expiration Request expiration date. + */ export async function tokenToXtz(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, xtzAmount: number, tokenAmount: number, expiration: Date): Promise { //(pair %tokenToXtz (pair (address :owner) (address :to)) (pair (nat :tokensSold) (pair (mutez :minXtzBought) (timestamp :deadline)))) const parameters = `(Pair (Pair "${keyStore.publicKeyHash}" "${keyStore.publicKeyHash}") (Pair ${tokenAmount} (Pair ${xtzAmount} "${expiration.toISOString()}")))`; @@ -127,6 +208,19 @@ export namespace DexterPoolHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + /** + * Untested function that should allow exchange of a token for a different token instead of xtz. + * + * @param server Destination Tezos node. + * @param signer + * @param keyStore + * @param contract + * @param fee + * @param otherPoolContract + * @param sellAmount + * @param buyAmount + * @param expiration Request expiration date. + */ export async function tokenToToken(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, otherPoolContract: string, sellAmount: number, buyAmount: number, expiration: Date): Promise { //(pair %tokenToToken (pair (address :outputDexterContract) (pair (nat :minTokensBought) (address :owner))) (pair (address :to) (pair (nat :tokensSold) (timestamp :deadline)))) const parameters = `(Pair (Pair "${otherPoolContract}" (Pair ${buyAmount} "${keyStore.publicKeyHash}")) (Pair "${keyStore.publicKeyHash}" (Pair ${sellAmount} "${expiration.toISOString()}")))`; @@ -136,6 +230,18 @@ export namespace DexterPoolHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + /** + * Approves a spender for a share of the liquidity balance on the given account. + * + * @param server Destination Tezos node. + * @param signer + * @param keyStore + * @param contract + * @param fee + * @param spender + * @param newAllowance + * @param currentAllowance + */ export async function approve(server: string, signer: Signer, keyStore: KeyStore, contract: string, fee: number, spender: string, newAllowance: number, currentAllowance: number): Promise { //(pair %approve (address :spender) (pair (nat :allowance) (nat :currentAllowance))) const parameters = `(Pair "${spender}" (Pair ${newAllowance} ${currentAllowance}))`; @@ -149,57 +255,76 @@ export namespace DexterPoolHelper { * Show pending applied operations against this contract in the mempool */ export async function previewTransactions() { - // + // TODO } /** + * Calculate the token requirement for the proposed XTZ deposit. * * @param xtzDeposit XTZ amount of the proposed transaction * @param tokenBalance Pool token balance * @param xtzBalance Pool XTZ balance - * @returns Token amount required for the matching XTZ balance + * @return {number} Matching token balance for the proposed deposit */ export function calcTokenLiquidityRequirement(xtzDeposit: number, tokenBalance: number, xtzBalance: number): number { return bigInt(xtzDeposit).multiply(bigInt(tokenBalance)).divide(bigInt(xtzBalance)).toJSNumber(); } /** - * Returns the token exchange rate for a given XTZ amount. + * XTZ/Token exchange rate for a given XTZ trade. * - * @param xtzDeposit - * @param tokenBalance - * @param xtzBalance + * @param xtzAmount Proposed XTZ deposit + * @param tokenBalance Current token balance in the pool + * @param xtzBalance Current XTZ balance in the pool */ - export function getTokenExchangeRate(xtzAmount: number, tokenBalance: number, xtzBalance: number) { + export function getTokenExchangeRate(xtzAmount: number, tokenBalance: number, xtzBalance: number, xtzDecimals: number = 6) { const n = bigInt(xtzAmount).multiply(bigInt(tokenBalance)).multiply(bigInt(ExchangeMultiplier)); - const d = bigInt(xtzBalance).multiply(bigInt(1000)).add(bigInt(xtzAmount).multiply(bigInt(ExchangeMultiplier))) + const d = bigInt(xtzBalance).multiply(bigInt(1000)).add(bigInt(xtzAmount).multiply(bigInt(ExchangeMultiplier))); + + const tokenAmount = n.divide(d); + const dm = tokenAmount.divmod(bigInt(xtzAmount)); + const f = dm.remainder.multiply(bigInt(10 ** xtzDecimals)).divide(bigInt(xtzAmount)); - return n.divide(d).divide(bigInt(xtzAmount)).toJSNumber(); + return { tokenAmount: tokenAmount.toJSNumber(), rate: parseFloat(`${dm.quotient.toJSNumber()}.${f.toJSNumber()}`) }; } /** - * Returns the XTZ exchange rate for a given token amount + * Token/XTZ exchange rate for a given token trade. * - * @param tokenAmount - * @param tokenBalance - * @param xtzBalance + * @param tokenAmount Proposed token deposit + * @param tokenBalance Current token balance in the pool + * @param xtzBalance Current XTZ balance in the pool */ - export function getXTZExchangeRate(tokenAmount: number, tokenBalance: number, xtzBalance: number) { + export function getXTZExchangeRate(tokenAmount: number, tokenBalance: number, xtzBalance: number, tokenDecimals: number = 6) { const n = bigInt(tokenAmount).multiply(bigInt(xtzBalance)).multiply(bigInt(ExchangeMultiplier)); const d = bigInt(tokenBalance).multiply(bigInt(1000)).add(bigInt(tokenAmount).multiply(bigInt(ExchangeMultiplier))) - return n.divide(d).divide(bigInt(tokenAmount)).toJSNumber(); + const xtzAmount = n.divide(d); + const dm = xtzAmount.divmod(bigInt(tokenAmount)); + const f = dm.remainder.multiply(bigInt(10 ** tokenDecimals)).divide(bigInt(tokenAmount)); + + return { xtzAmount: xtzAmount.toJSNumber(), rate: parseFloat(`${dm.quotient.toJSNumber()}.${f.toJSNumber()}`) }; } - //const lqtMinted = bigInt(xtzDeposit).multiply(bigInt(poolStorage.lqt_total)).divide(bigInt(poolStorage.xtzBalance)).toJSNumber(); + /** + * Returns the amount of liquidity tokens a particular XTZ deposit would receive. + * @param xtzDeposit + * @param liquidityBalance + * @param xtzBalance + */ + export function estimateLiquidityAmount(xtzDeposit: number, liquidityBalance: number, xtzBalance: number) { + return bigInt(xtzDeposit).multiply(bigInt(liquidityBalance)).divide(bigInt(xtzBalance)).toJSNumber(); + } /** * Estimates the cost of buying 1% share of the pool in terms of XTZ */ - export function estimateShareCost(xtzBalance: number, tokenBalance: number): { xtzCost: number, tokenCost: number } { - const xtzShare = bigInt(xtzBalance).divide(bigInt(100)).toJSNumber(); + export function estimateShareCost(xtzBalance: number, tokenBalance: number, liquidityBalance: number): { xtzCost: number, tokenCost: number } { + const xtzShare = bigInt(xtzBalance).divide(bigInt(99)).toJSNumber(); const tokenShare = calcTokenLiquidityRequirement(xtzShare, tokenBalance, xtzBalance); + // TODO: use estimateLiquidityAmount + return { xtzCost: xtzShare, tokenCost: tokenShare }; } } diff --git a/test/chain/tezos/contracts/DexterPoolHelper.spec.ts b/test/chain/tezos/contracts/DexterPoolHelper.spec.ts new file mode 100644 index 00000000..332bf176 --- /dev/null +++ b/test/chain/tezos/contracts/DexterPoolHelper.spec.ts @@ -0,0 +1,69 @@ +import { expect } from 'chai'; +import { DexterPoolHelper } from '../../../../src/chain/tezos/contracts/DexterPoolHelper'; + +describe('DexterPoolHelper test suite', () => { + it('calcTokenLiquidityRequirement tests', () => { + // TODO + //let result = DexterPoolHelper.calcTokenLiquidityRequirement(xtzDeposit: number, tokenBalance: number, xtzBalance: number) + }); + + /** + * Test samples retrieved from https://gitlab.com/camlcase-dev/dexter-integration/-/raw/master/xtz_to_token.json on 2020/Oct/21. + */ + it('getTokenExchangeRate tests', () => { + const camlCaseSamples = [ + { "xtz_pool": "1000000000", "token_pool": "250000", "xtz_in": "1000000", "token_out": "249", "slippage": "0.0040" }, + { "xtz_pool": "1000000000", "token_pool": "250000", "xtz_in": "2000000", "token_out": "497", "slippage": "0.0059" }, + { "xtz_pool": "1000000000", "token_pool": "250000", "xtz_in": "5000000", "token_out": "1240", "slippage": "0.0079" }, + { "xtz_pool": "1000000000", "token_pool": "250000", "xtz_in": "10000000", "token_out": "2467", "slippage": "0.0132" }, + { "xtz_pool": "1000000000", "token_pool": "250000", "xtz_in": "100000000", "token_out": "22665", "slippage": "0.0934" }, + { "xtz_pool": "355200000", "token_pool": "30000", "xtz_in": "1000000", "token_out": "83", "slippage": "0.0172" }, + { "xtz_pool": "355200000", "token_pool": "30000", "xtz_in": "34020000", "token_out": "2614", "slippage": "0.0902" }, + { "xtz_pool": "10000000000", "token_pool": "15200", "xtz_in": "10000000", "token_out": "15", "slippage": "0.0131" }, + { "xtz_pool": "10000000000", "token_pool": "15200", "xtz_in": "23100000", "token_out": "34", "slippage": "0.0316" }, + { "xtz_pool": "10000000000", "token_pool": "15200", "xtz_in": "67000000", "token_out": "100", "slippage": "0.01806" }, + { "xtz_pool": "10000000000", "token_pool": "15200", "xtz_in": "1050000", "token_out": "1", "slippage": "0.3734" }, + { "xtz_pool": "10000000000", "token_pool": "15200", "xtz_in": "4423000", "token_out": "6", "slippage": "0.1075" }, + { "xtz_pool": "103000000", "token_pool": "101000", "xtz_in": "1000000", "token_out": "968", "slippage": "0.0128" }, + { "xtz_pool": "10000000", "token_pool": "1000", "xtz_in": "2000000", "token_out": "166", "slippage": "0.1700" }, + { "xtz_pool": "12000000", "token_pool": "834", "xtz_in": "2500000", "token_out": "143", "slippage": "0.1769" }, + { "xtz_pool": "14500000", "token_pool": "691", "xtz_in": "6125000", "token_out": "204", "slippage": "0.3011" }, + { "xtz_pool": "14500000", "token_pool": "1234", "xtz_in": "5000000", "token_out": "315", "slippage": "0.2597" } ]; + + for (const sample of camlCaseSamples) { + const result = DexterPoolHelper.getTokenExchangeRate(Number(sample.xtz_in), Number(sample.token_pool), Number(sample.xtz_pool)); + + expect(result.tokenAmount).to.equal(Number(sample.token_out)); + } + }); + + /** + * * Test samples retrieved from https://gitlab.com/camlcase-dev/dexter-integration/-/raw/master/token_to_xtz.json on 2020/Oct/21. + */ + it('getXTZExchangeRate tests', () => { + const camlCaseSamples = [ + { "xtz_pool": "20000000", "token_pool": "1000", "token_in": "1000", "xtz_out": "9984977", "slippage": "0.5007" }, + { "xtz_pool": "20000000", "token_pool": "1000", "token_in": "100", "xtz_out": "1813221", "slippage": "0.0933" }, + { "xtz_pool": "20000000", "token_pool": "1000", "token_in": "10", "xtz_out": "197431", "slippage": "0.0128" }, + { "xtz_pool": "20000000", "token_pool": "1000", "token_in": "1", "xtz_out": "19920", "slippage": "0.0040" }, + { "xtz_pool": "20000000", "token_pool": "1000", "token_in": "240", "xtz_out": "3861597", "slippage": "0.1955" }, + { "xtz_pool": "20000000", "token_pool": "1000", "token_in": "116", "xtz_out": "2073262", "slippage": "0.1063" }, + { "xtz_pool": "20000000", "token_pool": "1000", "token_in": "923", "xtz_out": "9584586", "slippage": "0.4807" }, + { "xtz_pool": "19500000", "token_pool": "919", "token_in": "100", "xtz_out": "1908461", "slippage": "0.1005" }, + { "xtz_pool": "17591539", "token_pool": "1019", "token_in": "81", "xtz_out": "1291776", "slippage": "0.0762" } ]; + + for (const sample of camlCaseSamples) { + const result = DexterPoolHelper.getXTZExchangeRate(Number(sample.token_in), Number(sample.token_pool), Number(sample.xtz_pool)); + + expect(result.xtzAmount).to.equal(Number(sample.xtz_out)); + } + }); + + it('estimateLiquidityAmount tests', () => { + //estimateLiquidityAmount(xtzDeposit: number, liquidityBalance: number, xtzBalance: number) + }); + + it('estimateShareCost tests', () => { + //estimateShareCost(xtzBalance: number, tokenBalance: number): { xtzCost: number, tokenCost: number } + }); +}); From 3dd4828f34339c163b62d70230c8f7b3adbda9ca Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Tue, 10 Nov 2020 01:23:58 -0500 Subject: [PATCH 05/33] - impoved awaitOperationConfirmation failure conditions --- src/reporting/ConseilDataClient.ts | 1 + src/reporting/tezos/TezosConseilClient.ts | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/reporting/ConseilDataClient.ts b/src/reporting/ConseilDataClient.ts index 278f1c03..755a017c 100644 --- a/src/reporting/ConseilDataClient.ts +++ b/src/reporting/ConseilDataClient.ts @@ -26,6 +26,7 @@ export namespace ConseilDataClient { return fetch(url, { method: 'post', headers: { 'apiKey': serverInfo.apiKey, 'Content-Type': 'application/json' }, + cache: 'no-store', body: JSON.stringify(query) }) .then(r => { diff --git a/src/reporting/tezos/TezosConseilClient.ts b/src/reporting/tezos/TezosConseilClient.ts index f1829ae9..6a963595 100644 --- a/src/reporting/tezos/TezosConseilClient.ts +++ b/src/reporting/tezos/TezosConseilClient.ts @@ -1,8 +1,12 @@ -import { ConseilQueryBuilder } from "../ConseilQueryBuilder"; import { ConseilQuery, ConseilOperator, ConseilServerInfo, ConseilSortDirection } from "../../types/conseil/QueryTypes" -import { ConseilDataClient } from "../ConseilDataClient"; import { OperationKindType } from "../../types/tezos/TezosChainTypes"; import { ContractMapDetails, ContractMapDetailsItem } from '../../types/conseil/ConseilTezosTypes'; +import LogSelector from '../../utils/LoggerSelector'; + +import { ConseilDataClient } from "../ConseilDataClient"; +import { ConseilQueryBuilder } from "../ConseilQueryBuilder"; + +const log = LogSelector.log; /** * Functions for querying the Conseil backend REST API v2 for Tezos chain data. @@ -207,18 +211,29 @@ export namespace TezosConseilClient { */ export async function awaitOperationConfirmation(serverInfo: ConseilServerInfo, network: string, hash: string, duration: number, blocktime: number = 60): Promise { if (duration <= 0) { throw new Error('Invalid duration'); } + const initialLevel = (await getBlockHead(serverInfo, network))['level']; + const timeOffset = 180000; + const startTime = (new Date).getTime() - timeOffset; + const estimatedEndTime = startTime + timeOffset + duration * blocktime * 1000; + + log.debug(`TezosConseilClient.awaitOperationConfirmation looking for ${hash} since ${initialLevel} at ${(new Date(startTime).toUTCString())}, +${duration}`); + let currentLevel = initialLevel; let operationQuery = ConseilQueryBuilder.blankQuery(); operationQuery = ConseilQueryBuilder.addPredicate(operationQuery , 'operation_group_hash', ConseilOperator.EQ, [hash], false); - operationQuery = ConseilQueryBuilder.addPredicate(operationQuery , 'timestamp', ConseilOperator.AFTER, [(new Date).getTime() - 60000], false); + operationQuery = ConseilQueryBuilder.addPredicate(operationQuery , 'timestamp', ConseilOperator.AFTER, [startTime], false); operationQuery = ConseilQueryBuilder.setLimit(operationQuery, 1); while (initialLevel + duration > currentLevel) { const group = await getOperations(serverInfo, network, operationQuery); if (group.length > 0) { return group[0]; } + currentLevel = (await getBlockHead(serverInfo, network))['level']; + if (initialLevel + duration < currentLevel) { break; } + if ((new Date).getTime() > estimatedEndTime) { break; } + await new Promise(resolve => setTimeout(resolve, blocktime * 1000)); } From 7b38c5a35a830d58037dd72d0fcaa7df4698c372 Mon Sep 17 00:00:00 2001 From: othmane el kesri Date: Wed, 18 Nov 2020 13:08:02 +0100 Subject: [PATCH 06/33] feat(dryrun): implement TezosNodeWriter.dryRunOperation --- src/chain/tezos/TezosNodeWriter.ts | 47 ++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/chain/tezos/TezosNodeWriter.ts b/src/chain/tezos/TezosNodeWriter.ts index 872681e1..705692d7 100644 --- a/src/chain/tezos/TezosNodeWriter.ts +++ b/src/chain/tezos/TezosNodeWriter.ts @@ -649,12 +649,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. @@ -666,16 +662,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; @@ -701,6 +688,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} JSON-encoded response + */ + export async function dryRunOperation( + server: string, + chainid: string, + ...operations: TezosP2PMessageTypes.Operation[] + ): Promise { + 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. From e99eb05327ace688a3b83c6563994b93ba37ca16 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Tue, 24 Nov 2020 21:59:50 -0700 Subject: [PATCH 07/33] initial draft of token interactions --- package-lock.json | 2 +- src/chain/tezos/TezosNodeWriter.ts | 12 +- .../tezos/contracts/TezosContractUtils.ts | 15 +- .../tezos/contracts/WrappedTezosHelper.ts | 133 ++++++++++++++++++ src/index.ts | 1 + 5 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 src/chain/tezos/contracts/WrappedTezosHelper.ts diff --git a/package-lock.json b/package-lock.json index aac67cba..b0dac061 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "conseiljs", - "version": "5.0.5", + "version": "5.0.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/chain/tezos/TezosNodeWriter.ts b/src/chain/tezos/TezosNodeWriter.ts index 17751441..94d7c629 100644 --- a/src/chain/tezos/TezosNodeWriter.ts +++ b/src/chain/tezos/TezosNodeWriter.ts @@ -444,6 +444,8 @@ export namespace TezosNodeWriter { parameterFormat: TezosTypes.TezosParameterFormat = TezosTypes.TezosParameterFormat.Micheline, offset: number = 54 ) { + console.log("STOR: " + storageLimit) + const counter = await TezosNodeReader.getCounterForAccount(server, keyStore.publicKeyHash) + 1; const transaction = constructContractInvocationOperation(keyStore.publicKeyHash, counter, contract, amount, fee, storageLimit, gasLimit, entrypoint, parameters, parameterFormat); @@ -721,12 +723,12 @@ export namespace TezosNodeWriter { // in CARTHAGE and prior protocols activation failures are caught in the first branch } else { errors = arr.map(r => r.contents) - .map(o => + .map(o => o.map(c => c.metadata.operation_result) - .concat(o.flatMap(c => c.metadata.internal_operation_results).filter(c => !!c).map(c => c.result)) - .map(r => parseRPCOperationResult(r)) - .filter(i => i.length > 0) - .join(', ')) + .concat(o.flatMap(c => c.metadata.internal_operation_results).filter(c => !!c).map(c => c.result)) + .map(r => parseRPCOperationResult(r)) + .filter(i => i.length > 0) + .join(', ')) .join(', '); } } catch (err) { diff --git a/src/chain/tezos/contracts/TezosContractUtils.ts b/src/chain/tezos/contracts/TezosContractUtils.ts index 1295d52b..238a926b 100644 --- a/src/chain/tezos/contracts/TezosContractUtils.ts +++ b/src/chain/tezos/contracts/TezosContractUtils.ts @@ -7,19 +7,20 @@ import { TezosNodeReader } from '../TezosNodeReader'; * */ export namespace TezosContractUtils { -/** - * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. - * - * - * @param server Destination Tezos node. - * @param address Contract address to query. - */ + /** + * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. + * + * + * @param server Destination Tezos node. + * @param address Contract address to query. + */ export async function verifyDestination(server: string, address: string, expected: string): Promise { const contract = await TezosNodeReader.getAccountForBlock(server, 'head', address); if (!!!contract.script) { throw new Error(`No code found at ${address}`); } const k = Buffer.from(blakejs.blake2s(JSON.stringify(contract.script.code), null, 16)).toString('hex'); + console.log("Expected: " + k) if (k !== expected) { throw new Error(`Contract code hash "${k}" doesn't match expected ${expected}`); } diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts new file mode 100644 index 00000000..88677f62 --- /dev/null +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -0,0 +1,133 @@ +import { JSONPath } from 'jsonpath-plus'; + +import { KeyStore, Signer } from '../../../types/ExternalInterfaces'; +import * as TezosTypes from '../../../types/tezos/TezosChainTypes'; +import { TezosMessageUtils } from '../TezosMessageUtil'; +import { TezosNodeReader } from '../TezosNodeReader'; +import { TezosNodeWriter } from '../TezosNodeWriter'; +import { TezosContractUtils } from './TezosContractUtils'; + +/** The expected checksum for the Wrapped Tezos contracts. */ +const CONTRACT_CHECKSUMS = { + token: 'd48b45bd77d2300026fe617c5ba7670e' + + // TODO(keefertaylor): Implement additional checksums for core and oven contracts here. +} + +/** The expected checksum for the Wrapped Tezos scripts. */ +const SCRIPT_CHECKSUMS = { + // TODO(keefertaylor): Compute this checksum correctly. + token: '0e3e137841a959521324b4ce20ca2df7' + + // TODO(keefertaylor): Implement additional checksums for core and oven contracts here. +} + +/** + * Interface for the Wrapped XTZ Token and Oven implementation. + * + * @see {@link https://forum.tezosagora.org/t/wrapped-tezos/2195|wXTZ on Tezos Agora} + * + * The token represented by these contracts trades with symbol 'WXTZ' and is specified with 10^-6 precision. Put + * simply, 1 XTZ = 1 WXTZ, and 0.000_001 XTZ = 1 Mutez = 0.000_001 WXTZ. + * + * Canonical Data: + * - Delphinet: + * - Token Contract: KT1JYf7xjCJAqFDfNpuump9woSMaapy1WcMY + * - Token Balances Map ID: 14566 + * - TODO(keefertaylor): Add core / oven contracts here. + * TODO(keefertaylor): Add additional data for mainnet here. + * + * @author Keefer Taylor, Staker Services Ltd + */ +export namespace WrappedTezosHelper { + /** + * Verifies that contract code for Wrapped Tezos matches the expected code. + * + * Note: This function processes contracts in the Micheline format. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param tokenContractAddress The address of the token contract. + * @returns A boolean indicating if the code was the expected sum. + */ + export async function verifyDestination(nodeUrl: string, tokenContractAddress: string): Promise { + // TODO(keefertaylor): Verify checksums for core and oven contracts here. + return TezosContractUtils.verifyDestination(nodeUrl, tokenContractAddress, CONTRACT_CHECKSUMS.token); + } + + /** + * Verifies that Michelson script for Wrapped Tezos contracts matches the expected code. + * + * Note: This function processes scrips in Michelson format. + * + * @param tokenScript The address of the token contract. + * @returns A boolean indicating if the code was the expected sum. + */ + + export function verifyScript(tokenScript: string): boolean { + // TODO(keefertaylor): Verify checksums for core and oven scrips here. + return TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token); + } + + /** + * Get the balance of WXTZ tokens for an address. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param mapId The ID of the BigMap which contains balances. + * @param address The address to fetch the token balance for. + */ + export async function getAccountBalance(server: string, mapid: number, address: string): Promise { + const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData(address, 'address'), 'hex')); + const mapResult = await TezosNodeReader.getValueForBigMapKey(server, mapid, packedKey); + + if (mapResult === undefined) { throw new Error(`Map ${mapid} does not contain a record for ${address}`); } + + const numberString = JSONPath({ path: '$.int', json: mapResult }); + return Number(numberString); + } + + /** + * Transfer some WXTZ between addresses. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param signer A Signer for the sourceAddress. + * @param keystore A Keystore for the sourceAddress. + * @param tokenContractAddress The address of the token contract. + * @param fee The fee to use. + * @param sourceAddress The address which will send tokens. + * @param destinationAddress The address which will receive tokens. + * @param amount The amount of tokens to send. + * @param gasLimit The gas limit to use. + * @param storageLimit The storage limit to use. + * @returns A string representing the transaction hash. + */ + export async function transferBalance( + nodeUrl: string, + signer: Signer, + keystore: KeyStore, + tokenContractAddress: string, + fee: number, + sourceAddress: string, + destinationAddress: string, + amount: number, + gasLimit: number, + storageLimit: number + ): Promise { + const parameters = `Pair "${sourceAddress}" (Pair "${destinationAddress}" ${amount})`; + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation( + nodeUrl, + signer, + keystore, + tokenContractAddress, + 0, + fee, + storageLimit, + gasLimit, + 'transfer', + parameters, + TezosTypes.TezosParameterFormat.Michelson + ); + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } +} diff --git a/src/index.ts b/src/index.ts index 486b98cb..4db46337 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,6 +25,7 @@ export * from './chain/tezos/contracts/tzip12/ChainlinkTokenHelper'; export * from './chain/tezos/contracts/tzip12/MultiAssetTokenHelper'; export * from './chain/tezos/contracts/tzip12/SingleAssetTokenHelper'; export * from './chain/tezos/contracts/TzbtcTokenHelper'; +export * from './chain/tezos/contracts/WrappedTezosHelper'; export * from "./reporting/tezos/TezosConseilClient"; From 32a42fc339b96d2ff7c562e638c7ab9f1c33e76f Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Tue, 24 Nov 2020 22:05:49 -0700 Subject: [PATCH 08/33] revert file --- src/chain/tezos/TezosNodeWriter.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/chain/tezos/TezosNodeWriter.ts b/src/chain/tezos/TezosNodeWriter.ts index 94d7c629..17751441 100644 --- a/src/chain/tezos/TezosNodeWriter.ts +++ b/src/chain/tezos/TezosNodeWriter.ts @@ -444,8 +444,6 @@ export namespace TezosNodeWriter { parameterFormat: TezosTypes.TezosParameterFormat = TezosTypes.TezosParameterFormat.Micheline, offset: number = 54 ) { - console.log("STOR: " + storageLimit) - const counter = await TezosNodeReader.getCounterForAccount(server, keyStore.publicKeyHash) + 1; const transaction = constructContractInvocationOperation(keyStore.publicKeyHash, counter, contract, amount, fee, storageLimit, gasLimit, entrypoint, parameters, parameterFormat); @@ -723,12 +721,12 @@ export namespace TezosNodeWriter { // in CARTHAGE and prior protocols activation failures are caught in the first branch } else { errors = arr.map(r => r.contents) - .map(o => + .map(o => o.map(c => c.metadata.operation_result) - .concat(o.flatMap(c => c.metadata.internal_operation_results).filter(c => !!c).map(c => c.result)) - .map(r => parseRPCOperationResult(r)) - .filter(i => i.length > 0) - .join(', ')) + .concat(o.flatMap(c => c.metadata.internal_operation_results).filter(c => !!c).map(c => c.result)) + .map(r => parseRPCOperationResult(r)) + .filter(i => i.length > 0) + .join(', ')) .join(', '); } } catch (err) { From 7f40cff9a7c9db3bba44ff29d333927e45904150 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Tue, 24 Nov 2020 22:06:26 -0700 Subject: [PATCH 09/33] revert another file --- src/chain/tezos/contracts/TezosContractUtils.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/chain/tezos/contracts/TezosContractUtils.ts b/src/chain/tezos/contracts/TezosContractUtils.ts index 238a926b..1295d52b 100644 --- a/src/chain/tezos/contracts/TezosContractUtils.ts +++ b/src/chain/tezos/contracts/TezosContractUtils.ts @@ -7,20 +7,19 @@ import { TezosNodeReader } from '../TezosNodeReader'; * */ export namespace TezosContractUtils { - /** - * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. - * - * - * @param server Destination Tezos node. - * @param address Contract address to query. - */ +/** + * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. + * + * + * @param server Destination Tezos node. + * @param address Contract address to query. + */ export async function verifyDestination(server: string, address: string, expected: string): Promise { const contract = await TezosNodeReader.getAccountForBlock(server, 'head', address); if (!!!contract.script) { throw new Error(`No code found at ${address}`); } const k = Buffer.from(blakejs.blake2s(JSON.stringify(contract.script.code), null, 16)).toString('hex'); - console.log("Expected: " + k) if (k !== expected) { throw new Error(`Contract code hash "${k}" doesn't match expected ${expected}`); } From 635088c31559c7dc03fae29f8c3b3d3bd34d199b Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Tue, 24 Nov 2020 22:07:33 -0700 Subject: [PATCH 10/33] export for web --- src/index-web.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index-web.ts b/src/index-web.ts index 2d867cab..4f0660a6 100644 --- a/src/index-web.ts +++ b/src/index-web.ts @@ -20,6 +20,7 @@ export * from './chain/tezos/contracts/tzip12/ChainlinkTokenHelper'; export * from './chain/tezos/contracts/tzip12/MultiAssetTokenHelper'; export * from './chain/tezos/contracts/tzip12/SingleAssetTokenHelper'; export * from './chain/tezos/contracts/TzbtcTokenHelper'; +export * from './chain/tezos/contracts/WrappedTezosHelper'; export * from './reporting/tezos/TezosConseilClient'; export * from './reporting/ConseilDataClient'; From 35cf58e54f99cded0f1a1036157353239bb4249a Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Tue, 24 Nov 2020 21:14:24 -0800 Subject: [PATCH 11/33] Update WrappedTezosHelper.ts --- src/chain/tezos/contracts/WrappedTezosHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 88677f62..77da0b85 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -59,7 +59,7 @@ export namespace WrappedTezosHelper { * * Note: This function processes scrips in Michelson format. * - * @param tokenScript The address of the token contract. + * @param tokenScript The script of the token contract. * @returns A boolean indicating if the code was the expected sum. */ From dd16ba110b7dc31787b1a15ddc21be6b852d613c Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Tue, 24 Nov 2020 22:49:41 -0700 Subject: [PATCH 12/33] oven interactions --- .../tezos/contracts/WrappedTezosHelper.ts | 127 ++++++++++++++++-- 1 file changed, 117 insertions(+), 10 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 88677f62..17854b9c 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -9,17 +9,20 @@ import { TezosContractUtils } from './TezosContractUtils'; /** The expected checksum for the Wrapped Tezos contracts. */ const CONTRACT_CHECKSUMS = { - token: 'd48b45bd77d2300026fe617c5ba7670e' + token: 'd48b45bd77d2300026fe617c5ba7670e', + oven: '5e3c30607da21a0fc30f7be61afb15c7' - // TODO(keefertaylor): Implement additional checksums for core and oven contracts here. + // TODO(keefertaylor): Implement additional checksums for core contract here. } /** The expected checksum for the Wrapped Tezos scripts. */ const SCRIPT_CHECKSUMS = { // TODO(keefertaylor): Compute this checksum correctly. - token: '0e3e137841a959521324b4ce20ca2df7' + token: '', + // TODO(keefertaylor): Compute this checksum correctly. + oven: '', - // TODO(keefertaylor): Implement additional checksums for core and oven contracts here. + // TODO(keefertaylor): Implement additional checksums for core script here. } /** @@ -47,11 +50,19 @@ export namespace WrappedTezosHelper { * * @param nodeUrl The URL of the Tezos node which serves data. * @param tokenContractAddress The address of the token contract. + * @param ovenContractAddress The address of an oven contract. * @returns A boolean indicating if the code was the expected sum. */ - export async function verifyDestination(nodeUrl: string, tokenContractAddress: string): Promise { - // TODO(keefertaylor): Verify checksums for core and oven contracts here. - return TezosContractUtils.verifyDestination(nodeUrl, tokenContractAddress, CONTRACT_CHECKSUMS.token); + export async function verifyDestination( + nodeUrl: string, + tokenContractAddress: string, + ovenContractAddress: string + ): Promise { + // TODO(keefertaylor): Verify checksums for core contract here. + const tokenMatched = TezosContractUtils.verifyDestination(nodeUrl, tokenContractAddress, CONTRACT_CHECKSUMS.token) + const ovenMatched = TezosContractUtils.verifyDestination(nodeUrl, ovenContractAddress, CONTRACT_CHECKSUMS.oven) + + return tokenMatched && ovenMatched } /** @@ -59,13 +70,17 @@ export namespace WrappedTezosHelper { * * Note: This function processes scrips in Michelson format. * - * @param tokenScript The address of the token contract. + * @param tokenScript The script of the token contract. + * @param ovenScript The script of an oven contract. * @returns A boolean indicating if the code was the expected sum. */ export function verifyScript(tokenScript: string): boolean { - // TODO(keefertaylor): Verify checksums for core and oven scrips here. - return TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token); + // TODO(keefertaylor): Verify checksums for core script here. + const tokenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token) + const ovenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.oven) + + return tokenMatched && ovenMatched } /** @@ -130,4 +145,96 @@ export namespace WrappedTezosHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + + /** + * Deposit XTZ into an oven to mint WXTZ. + * + * WXTZ will be minted for the owner of the oven, *not* the source address. This allows bakers + * to payout delegated ovens. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param signer A Signer for the sourceAddress. + * @param keystore A Keystore for the sourceAddress. + * @param ovenAddress The address of the oven contract. + * @param fee The fee to use. + * @param amountMutez The amount of XTZ to deposit, specified in mutez. + * @param gasLimit The gas limit to use. + * @param storageLimit The storage limit to use. + * @returns A string representing the transaction hash. + */ + export async function depositToOven( + nodeUrl: string, + signer: Signer, + keystore: KeyStore, + ovenAddress: string, + fee: number, + amountMutez: number, + gasLimit: number, + storageLimit: number + ): Promise { + const parameters = 'Unit' + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation( + nodeUrl, + signer, + keystore, + ovenAddress, + amountMutez, + fee, + storageLimit, + gasLimit, + '', + parameters, + TezosTypes.TezosParameterFormat.Michelson + ) + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } + + /** + * Withdraw XTZ from an oven by repaying WXTZ. + * + * This operation will fail if: + * - The sending account is not the oven owner. + * - The sending account does not possess the equivalent amount of WXTZ to the withdrawal amount + * - The oven has less XTZ in it than is requested to be withdrawn. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param signer A Signer for the sourceAddress. + * @param keystore A Keystore for the sourceAddress. + * @param ovenAddress The address of the oven contract. + * @param fee The fee to use. + * @param amountMutez The amount of XTZ to withdraw, specified in mutez. + * @param gasLimit The gas limit to use. + * @param storageLimit The storage limit to use. + * @returns A string representing the transaction hash. + */ + export async function withdrawFromOven( + nodeUrl: string, + signer: Signer, + keystore: KeyStore, + ovenAddress: string, + fee: number, + amountMutez: number, + gasLimit: number, + storageLimit: number + ): Promise { + const parameters = `${amountMutez}` + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation( + nodeUrl, + signer, + keystore, + ovenAddress, + 0, + fee, + storageLimit, + gasLimit, + 'withdraw', + parameters, + TezosTypes.TezosParameterFormat.Michelson + ) + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } } From c0f25675fc8606d5af7c3c88f71422350a9aa328 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Tue, 24 Nov 2020 23:38:25 -0700 Subject: [PATCH 13/33] open vaults --- .../tezos/contracts/MurbardMultisigHelper.ts | 90 +++++++------- .../tezos/contracts/WrappedTezosHelper.ts | 113 ++++++++++++++++-- 2 files changed, 147 insertions(+), 56 deletions(-) diff --git a/src/chain/tezos/contracts/MurbardMultisigHelper.ts b/src/chain/tezos/contracts/MurbardMultisigHelper.ts index e99e5723..38578083 100644 --- a/src/chain/tezos/contracts/MurbardMultisigHelper.ts +++ b/src/chain/tezos/contracts/MurbardMultisigHelper.ts @@ -8,55 +8,55 @@ import { KeyStore, Signer } from '../../../types/ExternalInterfaces'; import * as TezosTypes from '../../../types/tezos/TezosChainTypes'; export namespace MurbardMultisigHelper { - /** - * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. - * - * @param server Destination Tezos node. - * @param address Contract address to query. - */ - export async function verifyDestination(server: string, address: string): Promise { - const contract = await TezosNodeReader.getAccountForBlock(server, 'head', address); + /** + * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. + * + * @param server Destination Tezos node. + * @param address Contract address to query. + */ + export async function verifyDestination(server: string, address: string): Promise { + const contract = await TezosNodeReader.getAccountForBlock(server, 'head', address); - if (!!!contract.script) { throw new Error(`No code found at ${address}`); } + if (!!!contract.script) { throw new Error(`No code found at ${address}`); } - const k = Buffer.from(blakejs.blake2s(JSON.stringify(contract.script.code), null, 16)).toString('hex'); + const k = Buffer.from(blakejs.blake2s(JSON.stringify(contract.script.code), null, 16)).toString('hex'); - if (k !== '914629850cfdad7b54a8c5a661d10bd0') { throw new Error(`Contract does not match the expected code hash: ${k}, '914629850cfdad7b54a8c5a661d10bd0'`); } + if (k !== '914629850cfdad7b54a8c5a661d10bd0') { throw new Error(`Contract does not match the expected code hash: ${k}, '914629850cfdad7b54a8c5a661d10bd0'`); } - return true; - } + return true; + } - /** - * In contrast to verifyDestination, this function uses compares Michelson hashes. - * - * @param script - */ - export function verifyScript(script: string): boolean { - const k = Buffer.from(blakejs.blake2s(TezosLanguageUtil.preProcessMichelsonScript(script).join('\n'), null, 16)).toString('hex'); + /** + * In contrast to verifyDestination, this function uses compares Michelson hashes. + * + * @param script + */ + export function verifyScript(script: string): boolean { + const k = Buffer.from(blakejs.blake2s(TezosLanguageUtil.preProcessMichelsonScript(script).join('\n'), null, 16)).toString('hex'); - if (k !== 'ffcad1e376a6c8915780fe6676aceec6') { throw new Error(`Contract does not match the expected code hash: ${k}, 'ffcad1e376a6c8915780fe6676aceec6'`); } + if (k !== 'ffcad1e376a6c8915780fe6676aceec6') { throw new Error(`Contract does not match the expected code hash: ${k}, 'ffcad1e376a6c8915780fe6676aceec6'`); } - return true; - } + return true; + } - export async function getSimpleStorage(server: string, address: string): Promise<{ counter: number, threshold: number, keys: string[] }> { - const storageResult = await TezosNodeReader.getContractStorage(server, address); + export async function getSimpleStorage(server: string, address: string): Promise<{ counter: number, threshold: number, keys: string[] }> { + const storageResult = await TezosNodeReader.getContractStorage(server, address); - return { - counter: Number(JSONPath({ path: '$.args[0].int', json: storageResult })[0]), - threshold: Number(JSONPath({ path: '$.args[1].args[0].int', json: storageResult })[0]), - keys: JSONPath({ path: '$.args[1].args[1]..string', json: storageResult }) - }; - } + return { + counter: Number(JSONPath({ path: '$.args[0].int', json: storageResult })[0]), + threshold: Number(JSONPath({ path: '$.args[1].args[0].int', json: storageResult })[0]), + keys: JSONPath({ path: '$.args[1].args[1]..string', json: storageResult }) + }; + } - /** - * Sample multi-sig contract retrieved in April 2020. - * https://github.com/murbard/smart-contracts/blob/master/multisig/michelson/multisig.tzip - */ - export async function deployContract(server: string, signer: Signer, keyStore: KeyStore, delegate: string, fee: number, amount: number, counter: number, threshold: number, keys: string[]): Promise { - if (threshold > keys.length) { throw new Error('Number of keys provided is lower than the threshold'); } + /** + * Sample multi-sig contract retrieved in April 2020. + * https://github.com/murbard/smart-contracts/blob/master/multisig/michelson/multisig.tzip + */ + export async function deployContract(server: string, signer: Signer, keyStore: KeyStore, delegate: string, fee: number, amount: number, counter: number, threshold: number, keys: string[]): Promise { + if (threshold > keys.length) { throw new Error('Number of keys provided is lower than the threshold'); } - const code = `parameter (pair (pair :payload (nat %counter) (or :action (pair :transfer (mutez %amount) (contract %dest unit)) (or (option %delegate key_hash) (pair %change_keys (nat %threshold) (list %keys key))))) (list %sigs (option signature))); + const code = `parameter (pair (pair :payload (nat %counter) (or :action (pair :transfer (mutez %amount) (contract %dest unit)) (or (option %delegate key_hash) (pair %change_keys (nat %threshold) (list %keys key))))) (list %sigs (option signature))); storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))); code { @@ -106,13 +106,13 @@ export namespace MurbardMultisigHelper { { DIP { SWAP ; CAR } ; SWAP ; PAIR ; SWAP }} ; PAIR }`; - const storage = `(Pair ${counter} (Pair ${threshold} { "${keys.join('" ; "') }" } ) )`; + const storage = `(Pair ${counter} (Pair ${threshold} { "${keys.join('" ; "')}" } ) )`; - const nodeResult = await TezosNodeWriter.sendContractOriginationOperation(server, signer, keyStore, amount, delegate, fee, 5_000, 120_000, code, storage, TezosTypes.TezosParameterFormat.Michelson); - return clearRPCOperationGroupHash(nodeResult['operationGroupID']); - } + const nodeResult = await TezosNodeWriter.sendContractOriginationOperation(server, signer, keyStore, amount, delegate, fee, 5_000, 120_000, code, storage, TezosTypes.TezosParameterFormat.Michelson); + return clearRPCOperationGroupHash(nodeResult['operationGroupID']); + } - function clearRPCOperationGroupHash(hash: string): string { - return hash.replace(/\"/g, '').replace(/\n/, ''); - } + function clearRPCOperationGroupHash(hash: string): string { + return hash.replace(/\"/g, '').replace(/\n/, ''); + } } diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 17854b9c..4fe88bb5 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -1,4 +1,6 @@ import { JSONPath } from 'jsonpath-plus'; +import base58Check from "bs58check"; +import * as blakejs from 'blakejs'; import { KeyStore, Signer } from '../../../types/ExternalInterfaces'; import * as TezosTypes from '../../../types/tezos/TezosChainTypes'; @@ -6,13 +8,13 @@ import { TezosMessageUtils } from '../TezosMessageUtil'; import { TezosNodeReader } from '../TezosNodeReader'; import { TezosNodeWriter } from '../TezosNodeWriter'; import { TezosContractUtils } from './TezosContractUtils'; +import { TezosParameterFormat } from '../../../types/tezos/TezosChainTypes'; /** The expected checksum for the Wrapped Tezos contracts. */ const CONTRACT_CHECKSUMS = { token: 'd48b45bd77d2300026fe617c5ba7670e', - oven: '5e3c30607da21a0fc30f7be61afb15c7' - - // TODO(keefertaylor): Implement additional checksums for core contract here. + oven: '5e3c30607da21a0fc30f7be61afb15c7', + core: '7b9b5b7e7f0283ff6388eb783e23c452' } /** The expected checksum for the Wrapped Tezos scripts. */ @@ -21,8 +23,19 @@ const SCRIPT_CHECKSUMS = { token: '', // TODO(keefertaylor): Compute this checksum correctly. oven: '', + // TODO(keefertaylor): Compute this checksum correctly. + core: '' +} + +/** + * Property bag containing the results of opening an oven. + */ +export type OpenOvenResult = { + // The operation hash of the request to open an oven. + operationHash: string - // TODO(keefertaylor): Implement additional checksums for core script here. + // The address of the new oven contract. + ovenAddress: string } /** @@ -51,18 +64,20 @@ export namespace WrappedTezosHelper { * @param nodeUrl The URL of the Tezos node which serves data. * @param tokenContractAddress The address of the token contract. * @param ovenContractAddress The address of an oven contract. + * @param coreContractAddress The address of the core contract. * @returns A boolean indicating if the code was the expected sum. */ export async function verifyDestination( nodeUrl: string, tokenContractAddress: string, - ovenContractAddress: string + ovenContractAddress: string, + coreContractAddress: string ): Promise { - // TODO(keefertaylor): Verify checksums for core contract here. const tokenMatched = TezosContractUtils.verifyDestination(nodeUrl, tokenContractAddress, CONTRACT_CHECKSUMS.token) const ovenMatched = TezosContractUtils.verifyDestination(nodeUrl, ovenContractAddress, CONTRACT_CHECKSUMS.oven) + const coreMatched = TezosContractUtils.verifyDestination(nodeUrl, coreContractAddress, CONTRACT_CHECKSUMS.core) - return tokenMatched && ovenMatched + return tokenMatched && ovenMatched && coreMatched } /** @@ -72,15 +87,16 @@ export namespace WrappedTezosHelper { * * @param tokenScript The script of the token contract. * @param ovenScript The script of an oven contract. + * @param coreScript The script of the core contract. * @returns A boolean indicating if the code was the expected sum. */ - export function verifyScript(tokenScript: string): boolean { - // TODO(keefertaylor): Verify checksums for core script here. + export function verifyScript(tokenScript: string, ovenScript, string, coreScript: string): boolean { const tokenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token) - const ovenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.oven) + const ovenMatched = TezosContractUtils.verifyScript(ovenScript, SCRIPT_CHECKSUMS.oven) + const coreMatched = TezosContractUtils.verifyScript(coreScript, SCRIPT_CHECKSUMS.core) - return tokenMatched && ovenMatched + return tokenMatched && ovenMatched && coreMatched } /** @@ -237,4 +253,79 @@ export namespace WrappedTezosHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + + export async function openOven( + nodeUrl: string, + signer: Signer, + keystore: KeyStore, + fee: number, + coreAddress: string, + gasLimit: number, + storageLimit: number + ): Promise { + const entryPoint = 'runEntrypointLambda' + const lambdaName = 'createOven' + const bytes = TezosMessageUtils.writePackedData(`Pair None "${keystore.publicKeyHash}"`, 'pair (option key_hash) address', TezosParameterFormat.Michelson) + const parameters = `Pair "${lambdaName}" 0x${bytes}` + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation( + nodeUrl, + signer, + keystore, + coreAddress, + 0, + fee, + storageLimit, + gasLimit, + entryPoint, + parameters, + TezosTypes.TezosParameterFormat.Michelson + ) + + const operationHash = TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + const ovenAddress = calculateContractAddress(operationHash, 0) + return { + operationHash, + ovenAddress + } + } + + /** + * Calculate the address of a contract that was originated. + * + * TODO(anonymoussprocket): This funcition is probably useful elsewhere in ConseilJS. Consider refactoring. + * + * @param operationHash The operation group hash. + * @param index The index of the origination operation in the operation group. + */ + 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 = [] + 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) + } + + 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 + } } From 204d2a2b801c8f2a2c79044bef24abf06f9262f6 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Tue, 24 Nov 2020 23:43:32 -0700 Subject: [PATCH 14/33] revert mubarb --- .../tezos/contracts/MurbardMultisigHelper.ts | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/chain/tezos/contracts/MurbardMultisigHelper.ts b/src/chain/tezos/contracts/MurbardMultisigHelper.ts index 38578083..e99e5723 100644 --- a/src/chain/tezos/contracts/MurbardMultisigHelper.ts +++ b/src/chain/tezos/contracts/MurbardMultisigHelper.ts @@ -8,55 +8,55 @@ import { KeyStore, Signer } from '../../../types/ExternalInterfaces'; import * as TezosTypes from '../../../types/tezos/TezosChainTypes'; export namespace MurbardMultisigHelper { - /** - * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. - * - * @param server Destination Tezos node. - * @param address Contract address to query. - */ - export async function verifyDestination(server: string, address: string): Promise { - const contract = await TezosNodeReader.getAccountForBlock(server, 'head', address); + /** + * Gets the contract code at the specified address at the head block and compares it to the known hash of the code. This function processes Micheline format contracts. + * + * @param server Destination Tezos node. + * @param address Contract address to query. + */ + export async function verifyDestination(server: string, address: string): Promise { + const contract = await TezosNodeReader.getAccountForBlock(server, 'head', address); - if (!!!contract.script) { throw new Error(`No code found at ${address}`); } + if (!!!contract.script) { throw new Error(`No code found at ${address}`); } - const k = Buffer.from(blakejs.blake2s(JSON.stringify(contract.script.code), null, 16)).toString('hex'); + const k = Buffer.from(blakejs.blake2s(JSON.stringify(contract.script.code), null, 16)).toString('hex'); - if (k !== '914629850cfdad7b54a8c5a661d10bd0') { throw new Error(`Contract does not match the expected code hash: ${k}, '914629850cfdad7b54a8c5a661d10bd0'`); } + if (k !== '914629850cfdad7b54a8c5a661d10bd0') { throw new Error(`Contract does not match the expected code hash: ${k}, '914629850cfdad7b54a8c5a661d10bd0'`); } - return true; - } + return true; + } - /** - * In contrast to verifyDestination, this function uses compares Michelson hashes. - * - * @param script - */ - export function verifyScript(script: string): boolean { - const k = Buffer.from(blakejs.blake2s(TezosLanguageUtil.preProcessMichelsonScript(script).join('\n'), null, 16)).toString('hex'); + /** + * In contrast to verifyDestination, this function uses compares Michelson hashes. + * + * @param script + */ + export function verifyScript(script: string): boolean { + const k = Buffer.from(blakejs.blake2s(TezosLanguageUtil.preProcessMichelsonScript(script).join('\n'), null, 16)).toString('hex'); - if (k !== 'ffcad1e376a6c8915780fe6676aceec6') { throw new Error(`Contract does not match the expected code hash: ${k}, 'ffcad1e376a6c8915780fe6676aceec6'`); } + if (k !== 'ffcad1e376a6c8915780fe6676aceec6') { throw new Error(`Contract does not match the expected code hash: ${k}, 'ffcad1e376a6c8915780fe6676aceec6'`); } - return true; - } + return true; + } - export async function getSimpleStorage(server: string, address: string): Promise<{ counter: number, threshold: number, keys: string[] }> { - const storageResult = await TezosNodeReader.getContractStorage(server, address); + export async function getSimpleStorage(server: string, address: string): Promise<{ counter: number, threshold: number, keys: string[] }> { + const storageResult = await TezosNodeReader.getContractStorage(server, address); - return { - counter: Number(JSONPath({ path: '$.args[0].int', json: storageResult })[0]), - threshold: Number(JSONPath({ path: '$.args[1].args[0].int', json: storageResult })[0]), - keys: JSONPath({ path: '$.args[1].args[1]..string', json: storageResult }) - }; - } + return { + counter: Number(JSONPath({ path: '$.args[0].int', json: storageResult })[0]), + threshold: Number(JSONPath({ path: '$.args[1].args[0].int', json: storageResult })[0]), + keys: JSONPath({ path: '$.args[1].args[1]..string', json: storageResult }) + }; + } - /** - * Sample multi-sig contract retrieved in April 2020. - * https://github.com/murbard/smart-contracts/blob/master/multisig/michelson/multisig.tzip - */ - export async function deployContract(server: string, signer: Signer, keyStore: KeyStore, delegate: string, fee: number, amount: number, counter: number, threshold: number, keys: string[]): Promise { - if (threshold > keys.length) { throw new Error('Number of keys provided is lower than the threshold'); } + /** + * Sample multi-sig contract retrieved in April 2020. + * https://github.com/murbard/smart-contracts/blob/master/multisig/michelson/multisig.tzip + */ + export async function deployContract(server: string, signer: Signer, keyStore: KeyStore, delegate: string, fee: number, amount: number, counter: number, threshold: number, keys: string[]): Promise { + if (threshold > keys.length) { throw new Error('Number of keys provided is lower than the threshold'); } - const code = `parameter (pair (pair :payload (nat %counter) (or :action (pair :transfer (mutez %amount) (contract %dest unit)) (or (option %delegate key_hash) (pair %change_keys (nat %threshold) (list %keys key))))) (list %sigs (option signature))); + const code = `parameter (pair (pair :payload (nat %counter) (or :action (pair :transfer (mutez %amount) (contract %dest unit)) (or (option %delegate key_hash) (pair %change_keys (nat %threshold) (list %keys key))))) (list %sigs (option signature))); storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))); code { @@ -106,13 +106,13 @@ export namespace MurbardMultisigHelper { { DIP { SWAP ; CAR } ; SWAP ; PAIR ; SWAP }} ; PAIR }`; - const storage = `(Pair ${counter} (Pair ${threshold} { "${keys.join('" ; "')}" } ) )`; + const storage = `(Pair ${counter} (Pair ${threshold} { "${keys.join('" ; "') }" } ) )`; - const nodeResult = await TezosNodeWriter.sendContractOriginationOperation(server, signer, keyStore, amount, delegate, fee, 5_000, 120_000, code, storage, TezosTypes.TezosParameterFormat.Michelson); - return clearRPCOperationGroupHash(nodeResult['operationGroupID']); - } + const nodeResult = await TezosNodeWriter.sendContractOriginationOperation(server, signer, keyStore, amount, delegate, fee, 5_000, 120_000, code, storage, TezosTypes.TezosParameterFormat.Michelson); + return clearRPCOperationGroupHash(nodeResult['operationGroupID']); + } - function clearRPCOperationGroupHash(hash: string): string { - return hash.replace(/\"/g, '').replace(/\n/, ''); - } + function clearRPCOperationGroupHash(hash: string): string { + return hash.replace(/\"/g, '').replace(/\n/, ''); + } } From 8e8a9f65378309ce11103da0ea9ebcc3c571849b Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Wed, 25 Nov 2020 01:45:49 -0500 Subject: [PATCH 15/33] - added WrappedTezosHelper.getSimpleStorage and related types --- .../tezos/contracts/WrappedTezosHelper.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 77da0b85..65501a85 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -22,6 +22,22 @@ const SCRIPT_CHECKSUMS = { // TODO(keefertaylor): Implement additional checksums for core and oven contracts here. } +export interface WrappedTezosStorage { + balanceMap: number; + approvalsMap: number; + supply: number; + administrator: string; + paused: boolean; + pauseGuardian: string; + outcomeMap: number; + swapMap: number; +} + +export interface WrappedTezosBalanceRecord { } +export interface WrappedTezosApprovalRecord { } +export interface WrappedTezosOutcomeRecord { } +export interface WrappedTezosSwapRecord { } + /** * Interface for the Wrapped XTZ Token and Oven implementation. * @@ -68,6 +84,28 @@ export namespace WrappedTezosHelper { return TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token); } + /** + * + * @param server + * @param address + */ + export async function getSimpleStorage(server: string, address: string): Promise { + const storageResult = await TezosNodeReader.getContractStorage(server, address); + + console.log(JSON.stringify(storageResult)); + + return { + balanceMap: Number(JSONPath({ path: '$.args[1].args[0].args[1].args[0].int', json: storageResult })[0]), + approvalsMap: Number(JSONPath({ path: '$.args[1].args[0].args[0].args[1].int', json: storageResult })[0]), + supply: Number(JSONPath({ path: '$.args[1].args[1].args[1].int', json: storageResult })[0]), + administrator: JSONPath({ path: '$.args[1].args[0].args[0].args[0].string', json: storageResult })[0], + paused: (JSONPath({ path: '$.args[1].args[1].args[0].prim', json: storageResult })[0]).toString().toLowerCase().startsWith('t'), + pauseGuardian: JSONPath({ path: '$.args[1].args[0].args[1].args[1].string', json: storageResult })[0], + outcomeMap: Number(JSONPath({ path: '$.args[0].args[0].int', json: storageResult })[0]), + swapMap: Number(JSONPath({ path: '$.args[0].args[1].int', json: storageResult })[0]) + }; + } + /** * Get the balance of WXTZ tokens for an address. * From 2979f64404b668ec80e2ba21fd8e09578b6f2931 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 09:40:33 -0700 Subject: [PATCH 16/33] refactor to helper --- src/chain/tezos/TezosMessageUtil.ts | 44 +++++++++++++++++++ .../tezos/contracts/WrappedTezosHelper.ts | 43 +----------------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/chain/tezos/TezosMessageUtil.ts b/src/chain/tezos/TezosMessageUtil.ts index 3acbcc74..6ac3d10a 100644 --- a/src/chain/tezos/TezosMessageUtil.ts +++ b/src/chain/tezos/TezosMessageUtil.ts @@ -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 = [] + 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 + } } diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 50f86274..a2e1fa46 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -1,6 +1,4 @@ import { JSONPath } from 'jsonpath-plus'; -import base58Check from "bs58check"; -import * as blakejs from 'blakejs'; import { KeyStore, Signer } from '../../../types/ExternalInterfaces'; import * as TezosTypes from '../../../types/tezos/TezosChainTypes'; @@ -321,49 +319,10 @@ export namespace WrappedTezosHelper { ) const operationHash = TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); - const ovenAddress = calculateContractAddress(operationHash, 0) + const ovenAddress = TezosMessageUtils.calculateContractAddress(operationHash, 0) return { operationHash, ovenAddress } } - - /** - * Calculate the address of a contract that was originated. - * - * TODO(anonymoussprocket): This funcition is probably useful elsewhere in ConseilJS. Consider refactoring. - * - * @param operationHash The operation group hash. - * @param index The index of the origination operation in the operation group. - */ - 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 = [] - 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) - } - - 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 - } } From 3bedc1552e9567322de80bd8dd92412b748ac1b8 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 09:44:26 -0700 Subject: [PATCH 17/33] add docs --- src/chain/tezos/contracts/WrappedTezosHelper.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index a2e1fa46..fa73dabe 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -290,6 +290,20 @@ export namespace WrappedTezosHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + /** + * Open a new oven. + * + * The oven's owner is assigned to the sender's address. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param signer A Signer for the sourceAddress. + * @param keystore A Keystore for the sourceAddress. + * @param fee The fee to use. + * @param coreAddress The address of the core contract. + * @param gasLimit The gas limit to use. + * @param storageLimit The storage limit to use. + * @returns A property bag of data about the operation. + */ export async function openOven( nodeUrl: string, signer: Signer, From 1e78d4871ec7ced06c01d35648ff38f7fd65d822 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 10:05:28 -0700 Subject: [PATCH 18/33] delegate / clear delegate functions --- .../tezos/contracts/WrappedTezosHelper.ts | 123 +++++++++++++----- 1 file changed, 94 insertions(+), 29 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index a2e1fa46..435d6910 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -113,40 +113,19 @@ export namespace WrappedTezosHelper { return tokenMatched && ovenMatched && coreMatched } - /** - * - * @param server - * @param address - */ - export async function getSimpleStorage(server: string, address: string): Promise { - const storageResult = await TezosNodeReader.getContractStorage(server, address); - - console.log(JSON.stringify(storageResult)); - - return { - balanceMap: Number(JSONPath({ path: '$.args[1].args[0].args[1].args[0].int', json: storageResult })[0]), - approvalsMap: Number(JSONPath({ path: '$.args[1].args[0].args[0].args[1].int', json: storageResult })[0]), - supply: Number(JSONPath({ path: '$.args[1].args[1].args[1].int', json: storageResult })[0]), - administrator: JSONPath({ path: '$.args[1].args[0].args[0].args[0].string', json: storageResult })[0], - paused: (JSONPath({ path: '$.args[1].args[1].args[0].prim', json: storageResult })[0]).toString().toLowerCase().startsWith('t'), - pauseGuardian: JSONPath({ path: '$.args[1].args[0].args[1].args[1].string', json: storageResult })[0], - outcomeMap: Number(JSONPath({ path: '$.args[0].args[0].int', json: storageResult })[0]), - swapMap: Number(JSONPath({ path: '$.args[0].args[1].int', json: storageResult })[0]) - }; - } - /** * Get the balance of WXTZ tokens for an address. * * @param nodeUrl The URL of the Tezos node which serves data. * @param mapId The ID of the BigMap which contains balances. - * @param address The address to fetch the token balance for. + * @param account The account to fetch the token balance for. + * @returns The balance of the account. */ - export async function getAccountBalance(server: string, mapid: number, address: string): Promise { - const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData(address, 'address'), 'hex')); + export async function getAccountBalance(server: string, mapid: number, account: string): Promise { + const packedKey = TezosMessageUtils.encodeBigMapKey(Buffer.from(TezosMessageUtils.writePackedData(account, 'address'), 'hex')); const mapResult = await TezosNodeReader.getValueForBigMapKey(server, mapid, packedKey); - if (mapResult === undefined) { throw new Error(`Map ${mapid} does not contain a record for ${address}`); } + if (mapResult === undefined) { throw new Error(`Map ${mapid} does not contain a record for ${account}`); } const numberString = JSONPath({ path: '$.int', json: mapResult }); return Number(numberString); @@ -165,7 +144,7 @@ export namespace WrappedTezosHelper { * @param amount The amount of tokens to send. * @param gasLimit The gas limit to use. * @param storageLimit The storage limit to use. - * @returns A string representing the transaction hash. + * @returns A string representing the operation hash. */ export async function transferBalance( nodeUrl: string, @@ -212,7 +191,7 @@ export namespace WrappedTezosHelper { * @param amountMutez The amount of XTZ to deposit, specified in mutez. * @param gasLimit The gas limit to use. * @param storageLimit The storage limit to use. - * @returns A string representing the transaction hash. + * @returns A string representing the operation hash. */ export async function depositToOven( nodeUrl: string, @@ -259,7 +238,7 @@ export namespace WrappedTezosHelper { * @param amountMutez The amount of XTZ to withdraw, specified in mutez. * @param gasLimit The gas limit to use. * @param storageLimit The storage limit to use. - * @returns A string representing the transaction hash. + * @returns A string representing the operation hash. */ export async function withdrawFromOven( nodeUrl: string, @@ -325,4 +304,90 @@ export namespace WrappedTezosHelper { ovenAddress } } + + /** + * Set the baker for an oven. + * + * This operation will fail if the sender is not the oven owner. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param signer A Signer for the sourceAddress. + * @param keystore A Keystore for the sourceAddress. + * @param fee The fee to use. + * @param gasLimit The gas limit to use. + * @param storageLimit The storage limit to use. + * @param ovenAddress The address of the oven contract. + * @param bakerAddress The address of the baker for the oven. + * @returns A string representing the operation hash. + */ + export async function setOvenBaker( + nodeUrl: string, + signer: Signer, + keystore: KeyStore, + fee: number, + gasLimit: number, + storageLimit: number, + ovenAddress: string, + bakerAddress: string + ): Promise { + const parameters = `Some "${bakerAddress}"` + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation( + nodeUrl, + signer, + keystore, + ovenAddress, + 0, + fee, + storageLimit, + gasLimit, + 'setDelegate', + parameters, + TezosTypes.TezosParameterFormat.Michelson + ) + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } + + /** + * Clear the baker for an oven. + * + * This operation will fail if the sender is not the oven owner. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param signer A Signer for the sourceAddress. + * @param keystore A Keystore for the sourceAddress. + * @param fee The fee to use. + * @param gasLimit The gas limit to use. + * @param storageLimit The storage limit to use. + * @param ovenAddress The address of the oven contract. + * @returns A string representing the operation hash. + */ + export async function clearOvenBaker( + nodeUrl: string, + signer: Signer, + keystore: KeyStore, + fee: number, + gasLimit: number, + storageLimit: number, + ovenAddress: string, + ): Promise { + const parameters = `None` + + const nodeResult = await TezosNodeWriter.sendContractInvocationOperation( + nodeUrl, + signer, + keystore, + ovenAddress, + 0, + fee, + storageLimit, + gasLimit, + 'setDelegate', + parameters, + TezosTypes.TezosParameterFormat.Michelson + ) + + return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); + } } From a4bfa2f9fe1aaeaf79e16c3dda38926308b881d4 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 10:11:40 -0700 Subject: [PATCH 19/33] revert changes in flight --- src/chain/tezos/TezosMessageUtil.ts | 44 ----------------------------- 1 file changed, 44 deletions(-) diff --git a/src/chain/tezos/TezosMessageUtil.ts b/src/chain/tezos/TezosMessageUtil.ts index 6ac3d10a..3acbcc74 100644 --- a/src/chain/tezos/TezosMessageUtil.ts +++ b/src/chain/tezos/TezosMessageUtil.ts @@ -552,48 +552,4 @@ 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 = [] - 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 - } } From 23eefafab83059035e8ae01f83137bf8100dd5d8 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 10:12:51 -0700 Subject: [PATCH 20/33] revert openopen --- .../tezos/contracts/WrappedTezosHelper.ts | 56 ++----------------- 1 file changed, 5 insertions(+), 51 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 435d6910..e4839976 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -11,8 +11,9 @@ import { TezosParameterFormat } from '../../../types/tezos/TezosChainTypes'; /** The expected checksum for the Wrapped Tezos contracts. */ const CONTRACT_CHECKSUMS = { token: 'd48b45bd77d2300026fe617c5ba7670e', - oven: '5e3c30607da21a0fc30f7be61afb15c7', - core: '7b9b5b7e7f0283ff6388eb783e23c452' + oven: '5e3c30607da21a0fc30f7be61afb15c7' + + // TODO(keefertaylor): Implement additional checksums for core contract here. } /** The expected checksum for the Wrapped Tezos scripts. */ @@ -20,20 +21,9 @@ const SCRIPT_CHECKSUMS = { // TODO(keefertaylor): Compute this checksum correctly. token: '', // TODO(keefertaylor): Compute this checksum correctly. - oven: '', - // TODO(keefertaylor): Compute this checksum correctly. - core: '' -} + oven: '' -/** - * Property bag containing the results of opening an oven. - */ -export type OpenOvenResult = { - // The operation hash of the request to open an oven. - operationHash: string - - // The address of the new oven contract. - ovenAddress: string + // TODO(keefertaylor): Implement additional checksums for core script here. } export interface WrappedTezosStorage { @@ -269,42 +259,6 @@ export namespace WrappedTezosHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } - export async function openOven( - nodeUrl: string, - signer: Signer, - keystore: KeyStore, - fee: number, - coreAddress: string, - gasLimit: number, - storageLimit: number - ): Promise { - const entryPoint = 'runEntrypointLambda' - const lambdaName = 'createOven' - const bytes = TezosMessageUtils.writePackedData(`Pair None "${keystore.publicKeyHash}"`, 'pair (option key_hash) address', TezosParameterFormat.Michelson) - const parameters = `Pair "${lambdaName}" 0x${bytes}` - - const nodeResult = await TezosNodeWriter.sendContractInvocationOperation( - nodeUrl, - signer, - keystore, - coreAddress, - 0, - fee, - storageLimit, - gasLimit, - entryPoint, - parameters, - TezosTypes.TezosParameterFormat.Michelson - ) - - const operationHash = TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); - const ovenAddress = TezosMessageUtils.calculateContractAddress(operationHash, 0) - return { - operationHash, - ovenAddress - } - } - /** * Set the baker for an oven. * From b71e8b87a1ba99d4300210bc8ac73b6e2d279394 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 10:14:02 -0700 Subject: [PATCH 21/33] more reverts --- src/chain/tezos/contracts/WrappedTezosHelper.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index e4839976..17012d81 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -6,7 +6,6 @@ import { TezosMessageUtils } from '../TezosMessageUtil'; import { TezosNodeReader } from '../TezosNodeReader'; import { TezosNodeWriter } from '../TezosNodeWriter'; import { TezosContractUtils } from './TezosContractUtils'; -import { TezosParameterFormat } from '../../../types/tezos/TezosChainTypes'; /** The expected checksum for the Wrapped Tezos contracts. */ const CONTRACT_CHECKSUMS = { @@ -21,9 +20,9 @@ const SCRIPT_CHECKSUMS = { // TODO(keefertaylor): Compute this checksum correctly. token: '', // TODO(keefertaylor): Compute this checksum correctly. - oven: '' + oven: '', - // TODO(keefertaylor): Implement additional checksums for core script here. + // TODO(keefertaylor): Implement additional checksums for core script here. } export interface WrappedTezosStorage { @@ -68,7 +67,6 @@ export namespace WrappedTezosHelper { * @param nodeUrl The URL of the Tezos node which serves data. * @param tokenContractAddress The address of the token contract. * @param ovenContractAddress The address of an oven contract. - * @param coreContractAddress The address of the core contract. * @returns A boolean indicating if the code was the expected sum. */ export async function verifyDestination( @@ -77,11 +75,11 @@ export namespace WrappedTezosHelper { ovenContractAddress: string, coreContractAddress: string ): Promise { + // TODO(keefertaylor): Verify checksums for core contract here. const tokenMatched = TezosContractUtils.verifyDestination(nodeUrl, tokenContractAddress, CONTRACT_CHECKSUMS.token) const ovenMatched = TezosContractUtils.verifyDestination(nodeUrl, ovenContractAddress, CONTRACT_CHECKSUMS.oven) - const coreMatched = TezosContractUtils.verifyDestination(nodeUrl, coreContractAddress, CONTRACT_CHECKSUMS.core) - return tokenMatched && ovenMatched && coreMatched + return tokenMatched && ovenMatched } /** @@ -91,16 +89,15 @@ export namespace WrappedTezosHelper { * * @param tokenScript The script of the token contract. * @param ovenScript The script of an oven contract. - * @param coreScript The script of the core contract. * @returns A boolean indicating if the code was the expected sum. */ export function verifyScript(tokenScript: string, ovenScript, string, coreScript: string): boolean { + // TODO(keefertaylor): Verify checksums for core script here. const tokenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token) const ovenMatched = TezosContractUtils.verifyScript(ovenScript, SCRIPT_CHECKSUMS.oven) - const coreMatched = TezosContractUtils.verifyScript(coreScript, SCRIPT_CHECKSUMS.core) - return tokenMatched && ovenMatched && coreMatched + return tokenMatched && ovenMatched } /** From 431b4f186be7ea1d57336f3e3d2e639ce3193fe1 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 10:14:37 -0700 Subject: [PATCH 22/33] more reverts --- src/chain/tezos/contracts/WrappedTezosHelper.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 17012d81..f978cee1 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -72,8 +72,7 @@ export namespace WrappedTezosHelper { export async function verifyDestination( nodeUrl: string, tokenContractAddress: string, - ovenContractAddress: string, - coreContractAddress: string + ovenContractAddress: string ): Promise { // TODO(keefertaylor): Verify checksums for core contract here. const tokenMatched = TezosContractUtils.verifyDestination(nodeUrl, tokenContractAddress, CONTRACT_CHECKSUMS.token) @@ -92,7 +91,7 @@ export namespace WrappedTezosHelper { * @returns A boolean indicating if the code was the expected sum. */ - export function verifyScript(tokenScript: string, ovenScript, string, coreScript: string): boolean { + export function verifyScript(tokenScript: string, ovenScript: string): boolean { // TODO(keefertaylor): Verify checksums for core script here. const tokenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token) const ovenMatched = TezosContractUtils.verifyScript(ovenScript, SCRIPT_CHECKSUMS.oven) From 1c551a32e4595ee65b302a77cc86f3b3bd330d05 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 10:16:28 -0700 Subject: [PATCH 23/33] more fixes --- src/chain/tezos/contracts/WrappedTezosHelper.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index f978cee1..94796ea5 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -90,7 +90,6 @@ export namespace WrappedTezosHelper { * @param ovenScript The script of an oven contract. * @returns A boolean indicating if the code was the expected sum. */ - export function verifyScript(tokenScript: string, ovenScript: string): boolean { // TODO(keefertaylor): Verify checksums for core script here. const tokenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token) From 29476b4817c0a60d4bcb40ebb3bc71295faa09ae Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 11:32:59 -0700 Subject: [PATCH 24/33] list ovens function --- .../tezos/contracts/WrappedTezosHelper.ts | 121 ++++++++++++------ src/reporting/tezos/TezosConseilClient.ts | 24 ++-- 2 files changed, 100 insertions(+), 45 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 88d054ff..4c1755c8 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -6,13 +6,15 @@ import { TezosMessageUtils } from '../TezosMessageUtil'; import { TezosNodeReader } from '../TezosNodeReader'; import { TezosNodeWriter } from '../TezosNodeWriter'; import { TezosContractUtils } from './TezosContractUtils'; +import { TezosConseilClient } from '../../../reporting/tezos/TezosConseilClient' +import { ConseilServerInfo } from 'types/conseil/QueryTypes'; +import { ContractMapDetailsItem } from 'types/conseil/ConseilTezosTypes'; /** The expected checksum for the Wrapped Tezos contracts. */ const CONTRACT_CHECKSUMS = { token: 'd48b45bd77d2300026fe617c5ba7670e', - oven: '5e3c30607da21a0fc30f7be61afb15c7' - - // TODO(keefertaylor): Implement additional checksums for core contract here. + oven: '5e3c30607da21a0fc30f7be61afb15c7', + core: '7b9b5b7e7f0283ff6388eb783e23c452' } /** The expected checksum for the Wrapped Tezos scripts. */ @@ -21,8 +23,8 @@ const SCRIPT_CHECKSUMS = { token: '', // TODO(keefertaylor): Compute this checksum correctly. oven: '', - - // TODO(keefertaylor): Implement additional checksums for core script here. + // TODO(keefertaylor): Compute this checksum correctly. + core: '' } export interface WrappedTezosStorage { @@ -41,6 +43,14 @@ export interface WrappedTezosApprovalRecord { } export interface WrappedTezosOutcomeRecord { } export interface WrappedTezosSwapRecord { } +/** + * Types for the Oven Map . + * + * Key: The oven's address. + * Value: The oven owner's address. + */ +export type OvenMapSchema = { key: string, value: string } + /** * Interface for the Wrapped XTZ Token and Oven implementation. * @@ -52,8 +62,9 @@ export interface WrappedTezosSwapRecord { } * Canonical Data: * - Delphinet: * - Token Contract: KT1JYf7xjCJAqFDfNpuump9woSMaapy1WcMY + * - Core Contract: KT1S98ELFTo6mdMBqhAVbGgKAVgLbdPP3AX8 * - Token Balances Map ID: 14566 - * - TODO(keefertaylor): Add core / oven contracts here. + * - Oven List Map ID: 14569 * TODO(keefertaylor): Add additional data for mainnet here. * * @author Keefer Taylor, Staker Services Ltd @@ -67,18 +78,20 @@ export namespace WrappedTezosHelper { * @param nodeUrl The URL of the Tezos node which serves data. * @param tokenContractAddress The address of the token contract. * @param ovenContractAddress The address of an oven contract. + * @param coreContractAddress The address of the core contract. * @returns A boolean indicating if the code was the expected sum. */ export async function verifyDestination( nodeUrl: string, tokenContractAddress: string, - ovenContractAddress: string + ovenContractAddress: string, + coreContractAddress: string ): Promise { - // TODO(keefertaylor): Verify checksums for core contract here. const tokenMatched = TezosContractUtils.verifyDestination(nodeUrl, tokenContractAddress, CONTRACT_CHECKSUMS.token) const ovenMatched = TezosContractUtils.verifyDestination(nodeUrl, ovenContractAddress, CONTRACT_CHECKSUMS.oven) + const coreMatched = TezosContractUtils.verifyDestination(nodeUrl, coreContractAddress, CONTRACT_CHECKSUMS.core) - return tokenMatched && ovenMatched + return tokenMatched && ovenMatched && coreMatched } /** @@ -88,37 +101,19 @@ export namespace WrappedTezosHelper { * * @param tokenScript The script of the token contract. * @param ovenScript The script of an oven contract. + * @param coreScript The script of the core contract. * @returns A boolean indicating if the code was the expected sum. */ - - export function verifyScript(tokenScript: string): boolean { - // TODO(keefertaylor): Verify checksums for core script here. + export function verifyScript( + tokenScript: string, + ovenScript: string, + coreScript: string + ): boolean { const tokenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token) - const ovenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.oven) + const ovenMatched = TezosContractUtils.verifyScript(ovenScript, SCRIPT_CHECKSUMS.oven) + const coreMatched = TezosContractUtils.verifyScript(coreScript, SCRIPT_CHECKSUMS.core) - return tokenMatched && ovenMatched - } - - /** - * - * @param server - * @param address - */ - export async function getSimpleStorage(server: string, address: string): Promise { - const storageResult = await TezosNodeReader.getContractStorage(server, address); - - console.log(JSON.stringify(storageResult)); - - return { - balanceMap: Number(JSONPath({ path: '$.args[1].args[0].args[1].args[0].int', json: storageResult })[0]), - approvalsMap: Number(JSONPath({ path: '$.args[1].args[0].args[0].args[1].int', json: storageResult })[0]), - supply: Number(JSONPath({ path: '$.args[1].args[1].args[1].int', json: storageResult })[0]), - administrator: JSONPath({ path: '$.args[1].args[0].args[0].args[0].string', json: storageResult })[0], - paused: (JSONPath({ path: '$.args[1].args[1].args[0].prim', json: storageResult })[0]).toString().toLowerCase().startsWith('t'), - pauseGuardian: JSONPath({ path: '$.args[1].args[0].args[1].args[1].string', json: storageResult })[0], - outcomeMap: Number(JSONPath({ path: '$.args[0].args[0].int', json: storageResult })[0]), - swapMap: Number(JSONPath({ path: '$.args[0].args[1].int', json: storageResult })[0]) - }; + return tokenMatched && ovenMatched && coreMatched } /** @@ -275,4 +270,58 @@ export namespace WrappedTezosHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } + + /** + * Retrieve a list of all oven addresses a user owns. + * + * @param serverInfo Connection info for Conseil. + * @param coreContractAddress The core contract address + * @param ovenOwner The oven owner to search for + * @param ovenListBigMapId The BigMap ID of the oven list. + */ + export async function listOvens( + serverInfo: ConseilServerInfo, + coreContractAddress: string, + ovenOwner: string, + ovenListBigMapId: number + ): Promise> { + // Fetch map data. + const mapData = await TezosConseilClient.getBigMapData(serverInfo, coreContractAddress) + if (mapData === undefined) { + throw new Error("Could not fetch map data!") + } + + // Find the Map that contains the oven list. + const { maps } = mapData + let ovenListMap: ContractMapDetailsItem | undefined = undefined + for (let i = 0; i < maps.length; i++) { + if (maps[i].definition.index === ovenListBigMapId) { + ovenListMap = maps[i] + break + } + } + if (ovenListMap === undefined) { + throw new Error("Could not find specified map ID!") + } + + // Conseil reports addresses as quoted michelson encoded hex prefixed + // with '0x'. Normalize these to base58check encoded addresses. + const { content } = ovenListMap + const normalizedOvenList: Array = content.map((oven: OvenMapSchema) => { + return { + key: TezosMessageUtils.readAddress(oven.key.replace(/\"/g, '').replace(/\n/, '').replace("0x", "")), + value: TezosMessageUtils.readAddress(oven.value.replace(/\"/g, '').replace(/\n/, '').replace("0x", "")) + } + }) + + // Filter oven list for ovens belonging to the owner. + const ownedOvens = normalizedOvenList.filter((oven: OvenMapSchema): boolean => { + return ovenOwner === oven.value + }) + + // Map filtered array to only contain oven addresses. + return ownedOvens.map((oven: OvenMapSchema) => { + return oven.key + }) + } } diff --git a/src/reporting/tezos/TezosConseilClient.ts b/src/reporting/tezos/TezosConseilClient.ts index 6a963595..3d6325cd 100644 --- a/src/reporting/tezos/TezosConseilClient.ts +++ b/src/reporting/tezos/TezosConseilClient.ts @@ -221,8 +221,8 @@ export namespace TezosConseilClient { let currentLevel = initialLevel; let operationQuery = ConseilQueryBuilder.blankQuery(); - operationQuery = ConseilQueryBuilder.addPredicate(operationQuery , 'operation_group_hash', ConseilOperator.EQ, [hash], false); - operationQuery = ConseilQueryBuilder.addPredicate(operationQuery , 'timestamp', ConseilOperator.AFTER, [startTime], false); + operationQuery = ConseilQueryBuilder.addPredicate(operationQuery, 'operation_group_hash', ConseilOperator.EQ, [hash], false); + operationQuery = ConseilQueryBuilder.addPredicate(operationQuery, 'timestamp', ConseilOperator.AFTER, [startTime], false); operationQuery = ConseilQueryBuilder.setLimit(operationQuery, 1); while (initialLevel + duration > currentLevel) { @@ -293,22 +293,28 @@ export namespace TezosConseilClient { if (ownerResult.length < 1) { return undefined; } + console.log("Got an owner result") + const definitionQuery = ConseilQueryBuilder.setLimit(ConseilQueryBuilder.addPredicate(ConseilQueryBuilder.blankQuery(), 'big_map_id', (ownerResult.length > 1 ? ConseilOperator.IN : ConseilOperator.EQ), ownerResult.map(r => r.big_map_id), false), 100); const definitionResult = await getTezosEntityData(serverInfo, serverInfo.network, 'big_maps', definitionQuery); + console.log("Got def result " + JSON.stringify(definitionResult)) + const contentQuery = ConseilQueryBuilder.setLimit(ConseilQueryBuilder.addFields(ConseilQueryBuilder.addPredicate(ConseilQueryBuilder.blankQuery(), 'big_map_id', (ownerResult.length > 1 ? ConseilOperator.IN : ConseilOperator.EQ), ownerResult.map(r => r.big_map_id), false), 'big_map_id', 'key', 'value'), 1000); const contentResult = await getTezosEntityData(serverInfo, serverInfo.network, 'big_map_contents', contentQuery); + console.log("Got content result " + JSON.stringify(contentResult)) + let maps: ContractMapDetailsItem[] = []; for (const d of definitionResult) { const definition = { index: Number(d['big_map_id']), key: d['key_type'], value: d['value_type'] }; let content: { key: string, value: string }[] = []; - for(const c of contentResult.filter(r => r['big_map_id'] === definition.index)) { - content.push({ key: JSON.stringify(c['key']), value: JSON.stringify(c['value'])}); + for (const c of contentResult.filter(r => r['big_map_id'] === definition.index)) { + content.push({ key: JSON.stringify(c['key']), value: JSON.stringify(c['value']) }); } - maps.push({definition, content}); + maps.push({ definition, content }); } return { contract, maps }; @@ -371,8 +377,8 @@ export namespace TezosConseilClient { if (i === 1) { return a && c['level'] === initialLevel - && c['hash'] === initialHash - && c['predecessor'] === blocks[i - 1]['hash']; + && c['hash'] === initialHash + && c['predecessor'] === blocks[i - 1]['hash']; } if (i === 0) { @@ -403,12 +409,12 @@ export namespace TezosConseilClient { export function getEntityQueryForId(id: string | number): { entity: string, query: ConseilQuery } { let q = ConseilQueryBuilder.setLimit(ConseilQueryBuilder.blankQuery(), 1); - if (typeof id === 'number') { + if (typeof id === 'number') { const n = Number(id); if (n < 0) { throw new Error('Invalid numeric id parameter'); } return { entity: BLOCKS, query: ConseilQueryBuilder.addPredicate(q, 'level', ConseilOperator.EQ, [id], false) }; - } else if (typeof id === 'string') { + } else if (typeof id === 'string') { const s = String(id); if (s.startsWith('tz1') || s.startsWith('tz2') || s.startsWith('tz3') || s.startsWith('KT1')) { From d963103be174c8508c31b7095e0430e9609d6e00 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 11:36:25 -0700 Subject: [PATCH 25/33] revert some debugging --- src/reporting/tezos/TezosConseilClient.ts | 24 +++++++++-------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/reporting/tezos/TezosConseilClient.ts b/src/reporting/tezos/TezosConseilClient.ts index 3d6325cd..6a963595 100644 --- a/src/reporting/tezos/TezosConseilClient.ts +++ b/src/reporting/tezos/TezosConseilClient.ts @@ -221,8 +221,8 @@ export namespace TezosConseilClient { let currentLevel = initialLevel; let operationQuery = ConseilQueryBuilder.blankQuery(); - operationQuery = ConseilQueryBuilder.addPredicate(operationQuery, 'operation_group_hash', ConseilOperator.EQ, [hash], false); - operationQuery = ConseilQueryBuilder.addPredicate(operationQuery, 'timestamp', ConseilOperator.AFTER, [startTime], false); + operationQuery = ConseilQueryBuilder.addPredicate(operationQuery , 'operation_group_hash', ConseilOperator.EQ, [hash], false); + operationQuery = ConseilQueryBuilder.addPredicate(operationQuery , 'timestamp', ConseilOperator.AFTER, [startTime], false); operationQuery = ConseilQueryBuilder.setLimit(operationQuery, 1); while (initialLevel + duration > currentLevel) { @@ -293,28 +293,22 @@ export namespace TezosConseilClient { if (ownerResult.length < 1) { return undefined; } - console.log("Got an owner result") - const definitionQuery = ConseilQueryBuilder.setLimit(ConseilQueryBuilder.addPredicate(ConseilQueryBuilder.blankQuery(), 'big_map_id', (ownerResult.length > 1 ? ConseilOperator.IN : ConseilOperator.EQ), ownerResult.map(r => r.big_map_id), false), 100); const definitionResult = await getTezosEntityData(serverInfo, serverInfo.network, 'big_maps', definitionQuery); - console.log("Got def result " + JSON.stringify(definitionResult)) - const contentQuery = ConseilQueryBuilder.setLimit(ConseilQueryBuilder.addFields(ConseilQueryBuilder.addPredicate(ConseilQueryBuilder.blankQuery(), 'big_map_id', (ownerResult.length > 1 ? ConseilOperator.IN : ConseilOperator.EQ), ownerResult.map(r => r.big_map_id), false), 'big_map_id', 'key', 'value'), 1000); const contentResult = await getTezosEntityData(serverInfo, serverInfo.network, 'big_map_contents', contentQuery); - console.log("Got content result " + JSON.stringify(contentResult)) - let maps: ContractMapDetailsItem[] = []; for (const d of definitionResult) { const definition = { index: Number(d['big_map_id']), key: d['key_type'], value: d['value_type'] }; let content: { key: string, value: string }[] = []; - for (const c of contentResult.filter(r => r['big_map_id'] === definition.index)) { - content.push({ key: JSON.stringify(c['key']), value: JSON.stringify(c['value']) }); + for(const c of contentResult.filter(r => r['big_map_id'] === definition.index)) { + content.push({ key: JSON.stringify(c['key']), value: JSON.stringify(c['value'])}); } - maps.push({ definition, content }); + maps.push({definition, content}); } return { contract, maps }; @@ -377,8 +371,8 @@ export namespace TezosConseilClient { if (i === 1) { return a && c['level'] === initialLevel - && c['hash'] === initialHash - && c['predecessor'] === blocks[i - 1]['hash']; + && c['hash'] === initialHash + && c['predecessor'] === blocks[i - 1]['hash']; } if (i === 0) { @@ -409,12 +403,12 @@ export namespace TezosConseilClient { export function getEntityQueryForId(id: string | number): { entity: string, query: ConseilQuery } { let q = ConseilQueryBuilder.setLimit(ConseilQueryBuilder.blankQuery(), 1); - if (typeof id === 'number') { + if (typeof id === 'number') { const n = Number(id); if (n < 0) { throw new Error('Invalid numeric id parameter'); } return { entity: BLOCKS, query: ConseilQueryBuilder.addPredicate(q, 'level', ConseilOperator.EQ, [id], false) }; - } else if (typeof id === 'string') { + } else if (typeof id === 'string') { const s = String(id); if (s.startsWith('tz1') || s.startsWith('tz2') || s.startsWith('tz3') || s.startsWith('KT1')) { From 9dd9e6f8d19c55cc44c2a85977887e10280c38e0 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 17:26:11 -0700 Subject: [PATCH 26/33] more merges --- src/chain/tezos/TezosMessageUtil.ts | 44 +++++++++++++++++++ .../tezos/contracts/WrappedTezosHelper.ts | 38 +++++++++++----- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/chain/tezos/TezosMessageUtil.ts b/src/chain/tezos/TezosMessageUtil.ts index 3acbcc74..5d541338 100644 --- a/src/chain/tezos/TezosMessageUtil.ts +++ b/src/chain/tezos/TezosMessageUtil.ts @@ -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 = [] + 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 + } } diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index ef0f58a5..5133dcaf 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -6,13 +6,13 @@ import { TezosMessageUtils } from '../TezosMessageUtil'; import { TezosNodeReader } from '../TezosNodeReader'; import { TezosNodeWriter } from '../TezosNodeWriter'; import { TezosContractUtils } from './TezosContractUtils'; +import { TezosParameterFormat } from '../../../types/tezos/TezosChainTypes'; /** The expected checksum for the Wrapped Tezos contracts. */ const CONTRACT_CHECKSUMS = { token: 'd48b45bd77d2300026fe617c5ba7670e', - oven: '5e3c30607da21a0fc30f7be61afb15c7' - - // TODO(keefertaylor): Implement additional checksums for core contract here. + oven: '5e3c30607da21a0fc30f7be61afb15c7', + core: '7b9b5b7e7f0283ff6388eb783e23c452' } /** The expected checksum for the Wrapped Tezos scripts. */ @@ -21,8 +21,19 @@ const SCRIPT_CHECKSUMS = { token: '', // TODO(keefertaylor): Compute this checksum correctly. oven: '', + // TODO(keefertaylor): Compute this checksum correctly. + core: '' +} + +/** + * Property bag containing the results of opening an oven. + */ +export type OpenOvenResult = { + // The operation hash of the request to open an oven. + operationHash: string - // TODO(keefertaylor): Implement additional checksums for core script here. + // The address of the new oven contract. + ovenAddress: string } export interface WrappedTezosStorage { @@ -67,18 +78,20 @@ export namespace WrappedTezosHelper { * @param nodeUrl The URL of the Tezos node which serves data. * @param tokenContractAddress The address of the token contract. * @param ovenContractAddress The address of an oven contract. + * @param coreContractAddress The address of the core contract. * * @returns A boolean indicating if the code was the expected sum. */ export async function verifyDestination( nodeUrl: string, tokenContractAddress: string, - ovenContractAddress: string + ovenContractAddress: string, + coreContractAddress: string ): Promise { - // TODO(keefertaylor): Verify checksums for core contract here. const tokenMatched = TezosContractUtils.verifyDestination(nodeUrl, tokenContractAddress, CONTRACT_CHECKSUMS.token) const ovenMatched = TezosContractUtils.verifyDestination(nodeUrl, ovenContractAddress, CONTRACT_CHECKSUMS.oven) + const coreMatched = TezosContractUtils.verifyDestination(nodeUrl, coreContractAddress, CONTRACT_CHECKSUMS.core) - return tokenMatched && ovenMatched + return tokenMatched && ovenMatched && coreMatched } /** @@ -88,14 +101,19 @@ export namespace WrappedTezosHelper { * * @param tokenScript The script of the token contract. * @param ovenScript The script of an oven contract. + * @param coreScript The script of the core contract. * @returns A boolean indicating if the code was the expected sum. */ - export function verifyScript(tokenScript: string, ovenScript: string): boolean { - // TODO(keefertaylor): Verify checksums for core script here. + export function verifyScript( + tokenScript: string, + ovenScript: string, + coreScript: string + ): boolean { const tokenMatched = TezosContractUtils.verifyScript(tokenScript, SCRIPT_CHECKSUMS.token) const ovenMatched = TezosContractUtils.verifyScript(ovenScript, SCRIPT_CHECKSUMS.oven) + const coreMatched = TezosContractUtils.verifyScript(coreScript, SCRIPT_CHECKSUMS.core) - return tokenMatched && ovenMatched + return tokenMatched && ovenMatched && coreMatched } /** From 29c41e21ea41925de1dfb213dffc33520010e5ea Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 17:28:32 -0700 Subject: [PATCH 27/33] revert --- src/chain/tezos/TezosMessageUtil.ts | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/chain/tezos/TezosMessageUtil.ts b/src/chain/tezos/TezosMessageUtil.ts index 5d541338..6ac3d10a 100644 --- a/src/chain/tezos/TezosMessageUtil.ts +++ b/src/chain/tezos/TezosMessageUtil.ts @@ -553,17 +553,17 @@ 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. + /** + * 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. + // 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. + // Merge the decoded buffer with the operation prefix. let decodedAndOperationPrefix: Array = [] for (let i = 0; i < decoded.length; i++) { decodedAndOperationPrefix.push(decoded[i]) @@ -575,19 +575,19 @@ export namespace TezosMessageUtils { index & 0x000000ff, ]) - // Hash and encode. + // Hash and encode. const hash = blakejs.blake2b(new Uint8Array(decodedAndOperationPrefix), null, 20) - const smartContractAddressPrefix = new Uint8Array([2, 90, 121]) // KT1 + 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. + /** + * 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) From 447055091551f4c2047d2a4fcc3db4075ee8d7e3 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 17:30:06 -0700 Subject: [PATCH 28/33] restore function --- .../tezos/contracts/WrappedTezosHelper.ts | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 5133dcaf..711f66fa 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -21,15 +21,15 @@ const SCRIPT_CHECKSUMS = { token: '', // TODO(keefertaylor): Compute this checksum correctly. oven: '', - // TODO(keefertaylor): Compute this checksum correctly. + // TODO(keefertaylor): Compute this checksum correctly. core: '' } -/** - * Property bag containing the results of opening an oven. +/** + * Property bag containing the results of opening an oven. */ export type OpenOvenResult = { - // The operation hash of the request to open an oven. + // The operation hash of the request to open an oven. operationHash: string // The address of the new oven contract. @@ -78,7 +78,7 @@ export namespace WrappedTezosHelper { * @param nodeUrl The URL of the Tezos node which serves data. * @param tokenContractAddress The address of the token contract. * @param ovenContractAddress The address of an oven contract. - * @param coreContractAddress The address of the core contract. * + * @param coreContractAddress The address of the core contract. * @returns A boolean indicating if the code was the expected sum. */ export async function verifyDestination( @@ -116,6 +116,28 @@ export namespace WrappedTezosHelper { return tokenMatched && ovenMatched && coreMatched } + /** + * + * @param server + * @param address + */ + export async function getSimpleStorage(server: string, address: string): Promise { + const storageResult = await TezosNodeReader.getContractStorage(server, address); + + console.log(JSON.stringify(storageResult)); + + return { + balanceMap: Number(JSONPath({ path: '$.args[1].args[0].args[1].args[0].int', json: storageResult })[0]), + approvalsMap: Number(JSONPath({ path: '$.args[1].args[0].args[0].args[1].int', json: storageResult })[0]), + supply: Number(JSONPath({ path: '$.args[1].args[1].args[1].int', json: storageResult })[0]), + administrator: JSONPath({ path: '$.args[1].args[0].args[0].args[0].string', json: storageResult })[0], + paused: (JSONPath({ path: '$.args[1].args[1].args[0].prim', json: storageResult })[0]).toString().toLowerCase().startsWith('t'), + pauseGuardian: JSONPath({ path: '$.args[1].args[0].args[1].args[1].string', json: storageResult })[0], + outcomeMap: Number(JSONPath({ path: '$.args[0].args[0].int', json: storageResult })[0]), + swapMap: Number(JSONPath({ path: '$.args[0].args[1].int', json: storageResult })[0]) + }; + } + /** * Get the balance of WXTZ tokens for an address. * From 148e04a6bf6bdfd38765f308a10910d537f05848 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 17:34:44 -0700 Subject: [PATCH 29/33] polish --- .../tezos/contracts/WrappedTezosHelper.ts | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 711f66fa..e8fe9f36 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -78,7 +78,7 @@ export namespace WrappedTezosHelper { * @param nodeUrl The URL of the Tezos node which serves data. * @param tokenContractAddress The address of the token contract. * @param ovenContractAddress The address of an oven contract. - * @param coreContractAddress The address of the core contract. + * @param coreContractAddress The address of the core contract. * @returns A boolean indicating if the code was the expected sum. */ export async function verifyDestination( @@ -116,10 +116,10 @@ export namespace WrappedTezosHelper { return tokenMatched && ovenMatched && coreMatched } - /** - * - * @param server - * @param address + /** + * + * @param server + * @param address */ export async function getSimpleStorage(server: string, address: string): Promise { const storageResult = await TezosNodeReader.getContractStorage(server, address); @@ -294,7 +294,7 @@ export namespace WrappedTezosHelper { return TezosContractUtils.clearRPCOperationGroupHash(nodeResult.operationGroupID); } - /** + /** * Open a new oven. * * The oven's owner is assigned to the sender's address. @@ -345,20 +345,20 @@ export namespace WrappedTezosHelper { } /** - * Set the baker for an oven. - * - * This operation will fail if the sender is not the oven owner. - * - * @param nodeUrl The URL of the Tezos node which serves data. - * @param signer A Signer for the sourceAddress. - * @param keystore A Keystore for the sourceAddress. - * @param fee The fee to use. - * @param gasLimit The gas limit to use. - * @param storageLimit The storage limit to use. - * @param ovenAddress The address of the oven contract. - * @param bakerAddress The address of the baker for the oven. - * @returns A string representing the operation hash. - */ + * Set the baker for an oven. + * + * This operation will fail if the sender is not the oven owner. + * + * @param nodeUrl The URL of the Tezos node which serves data. + * @param signer A Signer for the sourceAddress. + * @param keystore A Keystore for the sourceAddress. + * @param fee The fee to use. + * @param gasLimit The gas limit to use. + * @param storageLimit The storage limit to use. + * @param ovenAddress The address of the oven contract. + * @param bakerAddress The address of the baker for the oven. + * @returns A string representing the operation hash. + */ export async function setOvenBaker( nodeUrl: string, signer: Signer, From 51b1dd8658b9c454183e5a28d087720cef9f09f6 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Wed, 25 Nov 2020 17:35:24 -0700 Subject: [PATCH 30/33] whitespace --- src/chain/tezos/contracts/WrappedTezosHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index e8fe9f36..02dc3192 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -118,7 +118,7 @@ export namespace WrappedTezosHelper { /** * - * @param server + * @param server * @param address */ export async function getSimpleStorage(server: string, address: string): Promise { From 7ba9f5cc9e443397985ffe46fe52223dfce6b3da Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Mon, 30 Nov 2020 11:27:05 -0700 Subject: [PATCH 31/33] default gas and storage limits --- .../tezos/contracts/WrappedTezosHelper.ts | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 02dc3192..b8a6a58a 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -180,8 +180,8 @@ export namespace WrappedTezosHelper { sourceAddress: string, destinationAddress: string, amount: number, - gasLimit: number, - storageLimit: number + gasLimit: number = 51_300, + storageLimit: number = 70 ): Promise { const parameters = `Pair "${sourceAddress}" (Pair "${destinationAddress}" ${amount})`; @@ -225,8 +225,8 @@ export namespace WrappedTezosHelper { ovenAddress: string, fee: number, amountMutez: number, - gasLimit: number, - storageLimit: number + gasLimit: number = 126_500, + storageLimit: number = 10 ): Promise { const parameters = 'Unit' @@ -272,8 +272,8 @@ export namespace WrappedTezosHelper { ovenAddress: string, fee: number, amountMutez: number, - gasLimit: number, - storageLimit: number + gasLimit: number = 121_000, + storageLimit: number = 0 ): Promise { const parameters = `${amountMutez}` @@ -314,8 +314,8 @@ export namespace WrappedTezosHelper { keystore: KeyStore, fee: number, coreAddress: string, - gasLimit: number, - storageLimit: number + gasLimit: number = 115_000, + storageLimit: number = 1100 ): Promise { const entryPoint = 'runEntrypointLambda' const lambdaName = 'createOven' @@ -353,10 +353,10 @@ export namespace WrappedTezosHelper { * @param signer A Signer for the sourceAddress. * @param keystore A Keystore for the sourceAddress. * @param fee The fee to use. - * @param gasLimit The gas limit to use. - * @param storageLimit The storage limit to use. * @param ovenAddress The address of the oven contract. * @param bakerAddress The address of the baker for the oven. + * @param gasLimit The gas limit to use. + * @param storageLimit The storage limit to use. * @returns A string representing the operation hash. */ export async function setOvenBaker( @@ -364,10 +364,10 @@ export namespace WrappedTezosHelper { signer: Signer, keystore: KeyStore, fee: number, - gasLimit: number, - storageLimit: number, ovenAddress: string, - bakerAddress: string + bakerAddress: string, + gasLimit: number = 19_500, + storageLimit: number = 0, ): Promise { const parameters = `Some "${bakerAddress}"` @@ -408,9 +408,9 @@ export namespace WrappedTezosHelper { signer: Signer, keystore: KeyStore, fee: number, - gasLimit: number, - storageLimit: number, ovenAddress: string, + gasLimit: number = 19_500, + storageLimit: number = 0, ): Promise { const parameters = `None` From d359d4c6613062f63f020a98d0eb93834b81a491 Mon Sep 17 00:00:00 2001 From: Keefer Taylor Date: Mon, 30 Nov 2020 11:30:10 -0700 Subject: [PATCH 32/33] fix params --- src/chain/tezos/contracts/WrappedTezosHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chain/tezos/contracts/WrappedTezosHelper.ts b/src/chain/tezos/contracts/WrappedTezosHelper.ts index 2f45be4f..74259b45 100644 --- a/src/chain/tezos/contracts/WrappedTezosHelper.ts +++ b/src/chain/tezos/contracts/WrappedTezosHelper.ts @@ -464,9 +464,9 @@ export namespace WrappedTezosHelper { * @param signer A Signer for the sourceAddress. * @param keystore A Keystore for the sourceAddress. * @param fee The fee to use. + * @param ovenAddress The address of the oven contract. * @param gasLimit The gas limit to use. * @param storageLimit The storage limit to use. - * @param ovenAddress The address of the oven contract. * @returns A string representing the operation hash. */ export async function clearOvenBaker( From 1df628460ce1f6a78b90459c35f44b725850cc99 Mon Sep 17 00:00:00 2001 From: anonymoussprocket Date: Mon, 30 Nov 2020 23:53:01 -0500 Subject: [PATCH 33/33] - doc update --- src/chain/tezos/TezosNodeReader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chain/tezos/TezosNodeReader.ts b/src/chain/tezos/TezosNodeReader.ts index 0e929f08..a11cca16 100644 --- a/src/chain/tezos/TezosNodeReader.ts +++ b/src/chain/tezos/TezosNodeReader.ts @@ -130,7 +130,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