Skip to content

WIP: Bincode code generator #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,7 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

.DS_Store
tools/bincode_generator/target
rust_print_encoded/target
208 changes: 208 additions & 0 deletions 1-create-identity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@

import * as Bincode from "./src/bincode.ts";
import * as DashBincode from "./2.0.0/generated_bincode.js"
import DashKeys from "dashkeys";

import * as KeyUtils from "./src/key-utils.js";
import { loadWallet } from "./src/cli.ts";
import { deriveAllCreateIdentityKeys } from "./src/asset_lock.ts";
import { createPlatformAssetLock } from "./src/asset_lock.ts";
import { connectToNode, TRPC } from "./src/rpc.ts"
import { NODE_ADDRESS, RPC_AUTH_URL } from "./src/constants.ts"
import { toHex } from "./src/hex.js"
import { base58 } from "./src/util/base58.ts"
import { findExistingIdentity } from "./src/identity.ts"


export async function step1CreateIdentity(walletPhrase: string, walletSalt: string, identityIndex: number) {
const rpc = new TRPC(RPC_AUTH_URL);
const nodeRpc = connectToNode(NODE_ADDRESS)

const walletKey = await loadWallet(walletPhrase, walletSalt);

const hdOpts = { version: "testnet" as const }; // TODO

const {
regFundKey,
changeKey,
assetKey,
masterKey,
otherKey,
} = await deriveAllCreateIdentityKeys(
hdOpts,
walletKey,
identityIndex,
);

// console.log("Asset WIF", assetWif, "(would be ephemeral, non-hd)");

// console.log(
// "regFundKey",
// await DashHd.toAddr(regFundKey.publicKey, { version: "testnet" }),
// );
// console.log(
// "changeKey",
// await DashHd.toAddr(changeKey.publicKey, { version: "testnet" }),
// );
// console.log(
// "assetKey",
// await DashHd.toAddr(assetKey.publicKey, { version: "testnet" }),
// );
// console.log(
// "masterKey",
// await DashHd.toAddr(masterKey.publicKey, { version: "testnet" }),
// );
// console.log(
// "masterKey priv wif",
// await DashHd.toWif(masterKey.privateKey!, { version: "testnet" }),
// );
// console.log(
// "otherKey",
// await DashHd.toAddr(otherKey.publicKey, { version: "testnet" }),
// );
// console.log();

const pkh = await DashKeys.pubkeyToPkh(masterKey.publicKey)
console.log('masterKey pkh', toHex(pkh))
const existingIdentity = await findExistingIdentity(nodeRpc, pkh)
if (existingIdentity) {
const existingIdentityV0: DashBincode.IdentityV0 = Bincode.match(existingIdentity, {
V0: i => i[0]
});
const existingIdentityId = existingIdentityV0.id[0][0];
console.log('Identity Already Created!', base58.encode(existingIdentityId))
process.exit(1);
}

const {
identityId,
txidHex,
assetLockProof,
} = await createPlatformAssetLock(hdOpts, regFundKey, changeKey, assetKey, rpc);

console.log();
console.log(`identityId:`, base58.encode(identityId));


const identityKeys = [masterKey, otherKey];
const identityPublicKeys: DashBincode.IdentityPublicKeyInCreation[] = [
DashBincode.IdentityPublicKeyInCreation.V0(
DashBincode.IdentityPublicKeyInCreationV0({
id: 0,
key_type: DashBincode.KeyType.ECDSA_SECP256K1(),
purpose: DashBincode.Purpose.AUTHENTICATION(),
security_level: DashBincode.SecurityLevel.MASTER(),
contract_bounds: undefined,
read_only: false,
data: DashBincode.BinaryData(masterKey.publicKey),
signature: DashBincode.BinaryData(new Uint8Array()),
}),
),
DashBincode.IdentityPublicKeyInCreation.V0(
DashBincode.IdentityPublicKeyInCreationV0({
id: 1,
key_type: DashBincode.KeyType.ECDSA_SECP256K1(),
purpose: DashBincode.Purpose.AUTHENTICATION(),
security_level: DashBincode.SecurityLevel.CRITICAL(),
contract_bounds: undefined,
read_only: false,
data: DashBincode.BinaryData(otherKey.publicKey),
signature: DashBincode.BinaryData(new Uint8Array()),
}),
),
];

const identityCreate = DashBincode.IdentityCreateTransitionV0({
asset_lock_proof: assetLockProof,
public_keys: identityPublicKeys,
identity_id: DashBincode.Identifier(
DashBincode.IdentifierBytes32(identityId),
),
user_fee_increase: 0,
signature: DashBincode.BinaryData(new Uint8Array()),
});

const stateTransition: DashBincode.StateTransition =
DashBincode.StateTransition.IdentityCreate(
DashBincode.IdentityCreateTransition.V0(identityCreate),
);
// console.log(`identityPublicKeys:`, identityPublicKeys);

const signableTransition = new Uint8Array(
Bincode.encode(DashBincode.StateTransition, stateTransition, {
signable: true,
}),
);

const signableTransitionHash = await KeyUtils.doubleSha256(signableTransition);

{
const magicSigBytes = await KeyUtils.magicSign({
privKeyBytes: assetKey.privateKey!,
doubleSha256Bytes: signableTransitionHash,
});

identityCreate.signature[0] = magicSigBytes;
}

for (let i = 0; i < identityKeys.length; i += 1) {
const key = identityKeys[i];
const stPub = identityCreate.public_keys[i];
const magicSigBytes = await KeyUtils.magicSign({
privKeyBytes: key.privateKey!,
doubleSha256Bytes: signableTransitionHash,
});

Bincode.match(stPub, {
V0: ({ 0: stPub0 }: { 0: any }) => {
stPub0.signature[0] = magicSigBytes;
},
});
}

const fullSigTransition = new Uint8Array(
Bincode.encode(DashBincode.StateTransition, stateTransition, {
signable: false,
}),
);
const transitionHash = await KeyUtils.sha256(fullSigTransition);

console.log("Broadcasting Identity Create Transition...")
try {
const response = await nodeRpc.platform.broadcastStateTransition({
stateTransition: fullSigTransition,
})
console.log('response', response.status, response.response);
} catch (e) {
console.error("Error: ", decodeURIComponent((e as any).message))
}

const identity = base58.encode(identityId);
console.log();
console.log(`https://testnet.platform-explorer.com/identity/${identity}`);
console.log(`https://testnet.platform-explorer.com/transaction/${toHex(transitionHash)}`);
}

if (typeof process === 'object' && process.argv[1] === import.meta.filename) {

import("dotenv").then(dotenv => {
dotenv.default.config({ path: ".env" });

let walletPhrase = process.env.DASH_WALLET_PHRASE!;
let walletSalt = process.env.DASH_WALLET_SALT ?? "";

const identityIndex = parseInt(process.argv[2], 10);
if (isNaN(identityIndex)) {
console.error("");
console.error("USAGE");
console.error(` ${process.argv[0]} ${process.argv[1]} <identity-index>`);
console.error("");
console.error("EXAMPLE");
console.error(` ${process.argv[0]} ${process.argv[1]} 0`);
console.error("");
process.exit(1);
}

step1CreateIdentity(walletPhrase, walletSalt, identityIndex);
})
}
Loading