Skip to content

Commit

Permalink
WIP: creates assetLockTx
Browse files Browse the repository at this point in the history
  • Loading branch information
coolaj86 committed Aug 23, 2024
1 parent 962ad2b commit 4c4ec40
Showing 1 changed file with 297 additions and 0 deletions.
297 changes: 297 additions & 0 deletions demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
"use strict";

let DashPhrase = require("dashphrase");
let DashHd = require("dashhd");
let DashKeys = require("dashkeys");
let Secp256k1 = require("@dashincubator/secp256k1");
let DashTx = require("dashtx");
let DashPlatform = require("./dashplatform.js");

// let DapiGrpc = require("@dashevo/dapi-grpc");
let Dpp = require("@dashevo/wasm-dpp");

const DIP13_ECDSA = 0;

let identityEcdsaPath = "";
{
// m/purpose'/coin_type'/feature'/subfeature'/keytype'/identityindex'/keyindex'
// ex: m/9'/5'/5'/0'/0'/<id>/<key>
let purposeDip13 = 9;
let coinDash = 5;
let featureId = 5;
let subfeatureKey = 0;
let keyType = DIP13_ECDSA;
identityEcdsaPath = `m/${purposeDip13}'/${coinDash}'/${featureId}'/${subfeatureKey}'/${keyType}'`;
}

/**
* @typedef KeyInfo
* @prop {String} address
* @prop {Uint8Array} privateKey
* @prop {Uint8Array} publicKey
* @prop {String} pubKeyHash
*/
/** @type Object.<String, KeyInfo> */
let keysMap = {};

/** @type {Required<import('dashtx').TxKeyUtils>} */
let keyUtils = {
sign: async function (privKeyBytes, hashBytes) {
let sigOpts = { canonical: true, extraEntropy: true };
let sigBytes = await Secp256k1.sign(hashBytes, privKeyBytes, sigOpts);
return sigBytes;
},
getPrivateKey: async function (input) {
if (!input.address) {
//throw new Error('should put the address on the input there buddy...');
console.warn("missing address:", input.txid, input.outputIndex);
//@ts-ignore - TODO update type
return null;
}

let keyInfo = keysMap[input.address];
return keyInfo.privateKey;
},

getPublicKey: async function (txInput, i) {
let privKeyBytes = await keyUtils.getPrivateKey(txInput, i);
if (!privKeyBytes) {
return null;
}
let pubKeyBytes = await keyUtils.toPublicKey(privKeyBytes);

return pubKeyBytes;
},

toPublicKey: async function (privKeyBytes) {
// TODO use secp256k1 directly
return await DashKeys.utils.toPublicKey(privKeyBytes);
},
};

async function main() {
let network = "testnet";

// let phrase = await DashPhrase.generate();
let phrase =
"casino reveal crop open ordinary garment spy pizza clown exercise poem enjoy";
let salt = "";
let seedBytes = await DashPhrase.toSeed(phrase, salt);
let walletKey = await DashHd.fromSeed(seedBytes);

let accountIndex = 0; // pick the desired account for paying the fee
let addressIndex = 8; // pick an address with funds
let accountKey = await walletKey.deriveAccount(accountIndex);
let use = DashHd.RECEIVE;
let xprvKey = await accountKey.deriveXKey(use);
let addressKey = await xprvKey.deriveAddress(addressIndex);
if (!addressKey.privateKey) {
throw new Error("not an error, just a lint hack");
}

let addr = await DashHd.toAddr(addressKey.publicKey, { version: network });
let pkhBytes = await DashKeys.addrToPkh(addr, {
//@ts-ignore
version: network,
});
let pkh = DashKeys.utils.bytesToHex(pkhBytes);
let wif = await DashHd.toWif(addressKey.privateKey, { version: network });
console.log();
console.log(`Address: ${addr}`);
console.log(`WIF: ${wif}`);

keysMap[addr] = {
address: addr,
publicKey: addressKey.publicKey,
privateKey: addressKey.privateKey,
pubKeyHash: pkh,
};

let rpcAuthUrl = "https://api:[email protected]";
let utxos = await DashTx.utils.rpc(rpcAuthUrl, "getaddressutxos", {
addresses: [addr],
});
let total = DashTx.sum(utxos);
console.log();
console.log(`utxos (${total})`);
console.log(utxos);

let creditOutputs = [{ satoshis: total - 10000, pubKeyHash: pkh }];
let totalCredits = DashTx.sum(creditOutputs);
let burnOutput = { satoshis: totalCredits, pubKeyHash: pkh };
//@ts-ignore - TODO add types
let assetLockScript = DashPlatform.Tx.packAssetLock({
creditOutputs,
});

const VERSION_PLATfORM = 3;
const TYPE_ASSET_LOCK = 8;
let txDraft = {
version: VERSION_PLATfORM,
type: TYPE_ASSET_LOCK,
inputs: utxos,
outputs: [burnOutput],
extraPayload: assetLockScript,
};
console.log();
console.log(`txDraft:`);
console.log(txDraft);

let dashTx = DashTx.create(keyUtils);
let txSigned = await dashTx.hashAndSignAll(txDraft);
console.log();
console.log(`txSigned:`);
console.log(txSigned);
}

async function createIdentitiyKeys() {
let idIndex = 0; // increment to first unused
let identityEcdsaKey = await DashHd.derivePath(walletKey, identityEcdsaPath);
let identityKey = await DashHd.deriveChild(
identityEcdsaKey,
idIndex,
DashHd.HARDENED,
);

const MASTER_KEY = 0;
const HIGH_AUTH_KEY = 1;
const CRITICAL_KEY = 2;
const TRANSFER_KEY = 3;
let keyDescs = [
{
id: MASTER_KEY,
securityLevel: Dpp.IdentityPublicKey.SECURITY_LEVELS.MASTER,
},
{
id: HIGH_AUTH_KEY,
securityLevel: Dpp.IdentityPublicKey.SECURITY_LEVELS.HIGH,
},
{
id: CRITICAL_KEY,
securityLevel: Dpp.IdentityPublicKey.SECURITY_LEVELS.CRITICAL,
},
{
id: TRANSFER_KEY,
purpose: Dpp.IdentityPublicKey.PURPOSES.TRANSFER,
securityLevel: Dpp.IdentityPublicKey.SECURITY_LEVELS.CRITICAL,
},
];

let keys = [];
let dppKeys = [];
for (let keyDesc of keyDescs) {
let key = await DashHd.deriveChild(
identityKey,
keyDesc.id,
DashHd.HARDENED,
);
keys.push(key);

let MAGIC_NUMBER_1 = 1; // TODO why?
let dppKey = new Dpp.IdentityPublicKey(MAGIC_NUMBER_1);
dppKey.setId(keyDesc.id);
dppKey.setData(key.publicKey);
if (keyDesc.purpose) {
dppKey.setPurpose(keyDesc.purpose);
}
dppKey.setSecurityLevel(keyDesc.securityLevel);
dppKeys.push(dppKey);
}
}

function getAllTheKeys() {
// Create Identity
const identity = dpp.identity.create(assetLockProof.createIdentifier(), [
masterKey,
highAuthKey,
criticalAuthKey,
transferKey,
]);

// Create ST
const identityCreateTransition = dpp.identity.createIdentityCreateTransition(
identity,
assetLockProof,
);

// Create key proofs
const [stMasterKey, stHighAuthKey, stCriticalAuthKey, stTransferKey] =
identityCreateTransition.getPublicKeys();

// Sign master key

identityCreateTransition.signByPrivateKey(
identityMasterPrivateKey.toBuffer(),
IdentityPublicKey.TYPES.ECDSA_SECP256K1,
);

stMasterKey.setSignature(identityCreateTransition.getSignature());

identityCreateTransition.setSignature(undefined);

// Sign high auth key

identityCreateTransition.signByPrivateKey(
identityHighAuthPrivateKey.toBuffer(),
IdentityPublicKey.TYPES.ECDSA_SECP256K1,
);

stHighAuthKey.setSignature(identityCreateTransition.getSignature());

identityCreateTransition.setSignature(undefined);

// Sign critical auth key

identityCreateTransition.signByPrivateKey(
identityCriticalAuthPrivateKey.toBuffer(),
IdentityPublicKey.TYPES.ECDSA_SECP256K1,
);

stCriticalAuthKey.setSignature(identityCreateTransition.getSignature());

identityCreateTransition.setSignature(undefined);

// Sign transfer key

identityCreateTransition.signByPrivateKey(
identityTransferPrivateKey.toBuffer(),
IdentityPublicKey.TYPES.ECDSA_SECP256K1,
);

stTransferKey.setSignature(identityCreateTransition.getSignature());

identityCreateTransition.setSignature(undefined);

// Set public keys back after updating their signatures
identityCreateTransition.setPublicKeys([
stMasterKey,
stHighAuthKey,
stCriticalAuthKey,
stTransferKey,
]);

// Sign and validate state transition

identityCreateTransition.signByPrivateKey(
assetLockPrivateKey.toBuffer(),
IdentityPublicKey.TYPES.ECDSA_SECP256K1,
);

// TODO(versioning): restore
// @ts-ignore
// const result = await dpp.stateTransition.validateBasic(
// identityCreateTransition,
// // TODO(v0.24-backport): get rid of this once decided
// // whether we need execution context in wasm bindings
// new StateTransitionExecutionContext(),
// );

// if (!result.isValid()) {
// const messages = result.getErrors().map((error) => error.message);
// throw new Error(`StateTransition is invalid - ${JSON.stringify(messages)}`);
// }

return { identity, identityCreateTransition, identityIndex };
}

main();

0 comments on commit 4c4ec40

Please sign in to comment.