Skip to content

Instantly share code, notes, and snippets.

@bkase
Last active June 9, 2021 12:26
Show Gist options
  • Save bkase/683382f1f98876be89bd05facb75bd96 to your computer and use it in GitHub Desktop.
Save bkase/683382f1f98876be89bd05facb75bd96 to your computer and use it in GitHub Desktop.
Generating an offline transaction for mina-generate-keypair keys

Generating an offline transaction

Before there is an official tool to directly generate an offline transaction with the standard mina-generate-keypair generated private key, we can instead convert the key to the client-sdk compatible format and then use the client-sdk to generate the transaction.

A while ago I shared this idea with @nholland94, who in turn made a script that I then tweaked to use Docker and created this one. Thanks @nholland94 !

@nholland94's script minimizes the time that the private key is unencrypted by immediately creating the transaction as soon as the key is dumped.

How to use

  1. Install NodeJS and yarn on your system

On MacOS in a Terminal session (Terminal.app):

brew install node
npm install -g yarn
  1. Install docker on your system

  2. Download this gist as a zip file and unzip and enter this directory in your Terminal.app

  3. Pull the latest version of the client-sdk (tested with 1.0.1)

yarn add @o1labs/client-sdk
  1. Copy in your private key

Put a keys/ folder containing your (password protected) private key with chmod 700 permissions (this should already be set properly if you generated your keys using the minaprotocol.com docs) in this directory.

  1. Edit the make-transaction.js to point to your key

Change the line in main() to set the privateKeyPath to your key. Keep the leading / at the beginning.

  1. Edit the make-transaction.js to form your transaction

Change these fields as appropriate for your transaction

{
    to: 'B62qoozSJ5Zjz8m3LtRnmoejs425H38LfU6kYTrsoPPVy9hzrLc5HBM', // the receiver of the payment
    amount: 10**9, // 1.0 mina -- in nanonmina (1 billion = 1.0 mina)
    fee: 1 * 10**7, // 0.01 mina -- in nanonmina (1 billion = 1.0 mina)
    nonce: 0 // the number of transactions you've made on this account already. you can find this in minaexplorer.com
}
  1. Open a new terminal session

On MacOS, this is the Terminal.app program (or your favorite)

  1. Export your private key password as an environment variable

Change mypassword below with your password

export CODA_PRIVKEY_PASS='mypassword'
  1. Run the script generating the transaction in that Terminal.app session
node make-transaction.js

This will make the transaction in a file called my-txn.json in this directory. You can view it with cat:

cat my-txn.json
  1. Broadcast using your favorite tool

For example, https://minaexplorer.com/broadcast-tx

const MinaSDK = require('@o1labs/client-sdk');
const fs = require('fs');
const process = require('process');
const child_process = require('child_process');
function run(cmd, env) {
return new Promise((resolve, reject) => {
child_process.exec(cmd, {env}, (error, stdout, stderr) => {
if(error) {
reject(error);
} else {
resolve(stdout.split("\n").filter((l) => l.length > 0));
}
});
});
}
async function loadKeypair(privateKeyPath) {
const readValue = (line) => line.split(': ')[1];
const lines = await run(`docker run --env CODA_PRIVKEY_PASS=${process.env.CODA_PRIVKEY_PASS} --interactive --rm --volume $(pwd)/keys:/keys --entrypoint /bin/bash minaprotocol/mina-daemon-baked:1.1.5-a42bdee -c 'mina advanced dump-keypair --privkey-path "${privateKeyPath}"'`);
const [pubkeyLine, privkeyLine] = lines.slice(lines.length-2, lines.length);
return {publicKey: readValue(pubkeyLine), privateKey: readValue(privkeyLine)};
}
async function makePayment(outputFile, {privateKeyPath, to, fee, amount, nonce}) {
const keypair = await loadKeypair(privateKeyPath);
const from = keypair.publicKey;
const signedPayment = MinaSDK.signPayment({
from,
to,
fee,
amount,
// memo,
nonce
}, keypair);
fs.writeFileSync(outputFile, JSON.stringify(signedPayment));
}
async function main() {
const privateKeyPath = '/keys/my-wallet'
await makePayment('my-txn.json', {
privateKeyPath,
to: 'B62qoozSJ5Zjz8m3LtRnmoejs425H38LfU6kYTrsoPPVy9hzrLc5HBM', // the receiver of the payment
amount: 10**9, // 1.0 mina -- in nanonmina (1 billion = 1.0 mina)
fee: 1 * 10**7, // 0.01 mina -- in nanonmina (1 billion = 1.0 mina)
nonce: 0 // the number of transactions you've made on this account already. you can find this in minaexplorer.com
});
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment