Created
July 4, 2020 11:24
-
-
Save abrkn/2e74afd5b82b37661cb03691ebb4e433 to your computer and use it in GitHub Desktop.
Move the remaining balance of a Tezos account to the specified destination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as Conseil from 'conseiljs'; | |
import { SoftSigner } from 'conseiljs-softsigner'; | |
import { ns } from '@sideshift/shared'; | |
import { | |
initializeConseil, | |
TezosRpcClient, | |
getTezosKeyStoreFromSecret, | |
createLogger, | |
} from '@sideshift/shared-node'; | |
// TODO: Remove magic constants | |
const DRAIN_COST = 50; | |
const CHAIN_ID = 'NetXdQprcVkpaWU'; | |
export type DrainTezosAccountOptions = { | |
/** | |
* The secret key of the source account. | |
*/ | |
secret: string; | |
destination: string; | |
rpc: TezosRpcClient; | |
/** | |
* The account used to estimate the fee. This can be any account that has | |
* a non-zero balance and is not a smart contract. The account will not | |
* be used in the actual operations submitted to the Tezos blockchain. | |
*/ | |
estimateAccount: string; | |
}; | |
/** | |
* Move the remaining balance of a Tezos account to the specified destination. | |
* @returns The operation group id when the source account has a non-zero balance else undefined | |
*/ | |
export const drainTezosAccount = async ({ | |
secret, | |
destination, | |
rpc, | |
estimateAccount, | |
}: DrainTezosAccountOptions): Promise<string | undefined> => { | |
const logger = createLogger({ name: 'tezos' }); | |
initializeConseil(); | |
const keyStore = await getTezosKeyStoreFromSecret(secret); | |
const signer = new SoftSigner(keyStore.secretKeyRaw); | |
const balanceUnits = await rpc.getBalance(keyStore.publicKeyHash); | |
if (ns.eq(balanceUnits, 0)) { | |
return undefined; | |
} | |
logger.debug(`Balance of ${keyStore.publicKeyHash}: ${balanceUnits} mutez`); | |
const isSourceRevealed = await Conseil.TezosNodeReader.isManagerKeyRevealedForAccount( | |
rpc.url, | |
keyStore.publicKeyHash | |
); | |
const prevCounterDestination = await Conseil.TezosNodeReader.getCounterForAccount( | |
rpc.url, | |
keyStore.publicKeyHash | |
); | |
const prevCounterEstimate = await Conseil.TezosNodeReader.getCounterForAccount( | |
rpc.url, | |
estimateAccount | |
); | |
const reveralOperation: Conseil.Reveal | undefined = isSourceRevealed | |
? undefined | |
: { | |
kind: 'reveal', | |
source: keyStore.publicKeyHash, | |
fee: '0', // Reveal Fee will be covered by the appended operation | |
counter: (prevCounterDestination + 1).toString(), | |
gas_limit: '10000', | |
storage_limit: '0', | |
public_key: keyStore.publicKey, | |
}; | |
const transactionOperationBase = { | |
destination, | |
storage_limit: '0', | |
kind: 'transaction', | |
}; | |
const transactionEstimateOperation: Conseil.Transaction = { | |
...transactionOperationBase, | |
amount: balanceUnits.toString(), | |
source: estimateAccount, | |
gas_limit: '800000', | |
fee: '5000', | |
counter: (prevCounterEstimate + 1).toString(), | |
}; | |
logger.debug(`Estimating transaction cost...`); | |
const transactionEstimate = await Conseil.TezosNodeWriter.estimateOperation( | |
rpc.url, | |
CHAIN_ID, | |
transactionEstimateOperation | |
); | |
const cost = transactionEstimate.gas + transactionEstimate.storageCost + DRAIN_COST; | |
logger.debug(`Estimated transaction cost: ${cost} mutez`); | |
const transactionCounter = (isSourceRevealed | |
? prevCounterDestination + 1 | |
: prevCounterDestination + 2 | |
).toString(); | |
const transactionOperation: Conseil.Transaction = { | |
...transactionOperationBase, | |
amount: ns.minus(balanceUnits, cost).toString(), | |
source: keyStore.publicKeyHash, | |
gas_limit: cost.toString(), | |
fee: cost.toString(), | |
counter: transactionCounter, | |
}; | |
const operations: Conseil.Operation[] = [transactionOperation]; | |
if (reveralOperation) { | |
operations.unshift(reveralOperation); | |
} | |
logger.debug(`Submitting transaction...`); | |
const response = await Conseil.TezosNodeWriter.sendOperation( | |
rpc.url, | |
operations, | |
(signer as unknown) as Conseil.Signer | |
); | |
const operationGroupId = JSON.parse(response.operationGroupID); | |
logger.debug(`Drained ${keyStore.publicKeyHash} in ${operationGroupId}`); | |
return operationGroupId; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment