@dfinity/hardware-wallet-cli 0.2.2 → 0.3.0-next-2023-08-28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/index.js +14 -0
- package/package.json +32 -12
- package/.github/CODEOWNERS +0 -2
- package/.prettierignore +0 -1
- package/build/index.js +0 -401
- package/build/src/ledger/identity.js +0 -218
- package/build/src/ledger/secp256k1.js +0 -90
- package/index.ts +0 -552
- package/src/ledger/identity.ts +0 -253
- package/src/ledger/secp256k1.ts +0 -117
- package/tsconfig.json +0 -15
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@ A CLI to interact with the Internet Computer App on Ledger Nano S/X devices.
|
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
- Install `node >= 18.13.0`.
|
|
8
|
+
- Install the CLI: `npm install -g @dfinity/hardware-wallet-cli`
|
|
9
|
+
- Run the CLI: `ic-hardware-wallet --help`
|
|
10
10
|
|
|
11
11
|
## USB connection issues with Ledger Live
|
|
12
12
|
|
|
@@ -27,5 +27,5 @@ To execute a command, you can use `npm run execute -- <args>`.
|
|
|
27
27
|
|
|
28
28
|
For example
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
- The command `ic-hardware-wallet --network https://nnsdapp.dfinity.network icp balance`.
|
|
31
|
+
- Would be `npm run execute -- --network https://nnsdapp.dfinity.network icp balance` for development.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var we=Object.create;var J=Object.defineProperty;var fe=Object.getOwnPropertyDescriptor;var he=Object.getOwnPropertyNames;var be=Object.getPrototypeOf,Ie=Object.prototype.hasOwnProperty;var Pe=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of he(e))!Ie.call(n,i)&&i!==t&&J(n,i,{get:()=>e[i],enumerable:!(r=fe(e,i))||r.enumerable});return n};var D=(n,e,t)=>(t=n!=null?we(be(n)):{},Pe(e||!n||!n.__esModule?J(t,"default",{value:n,enumerable:!0}):t,n));var a=require("commander"),s=require("@dfinity/nns");var b=require("commander"),k=require("@dfinity/nns"),ce=require("@dfinity/principal");var K=require("@dfinity/agent"),z=require("@dfinity/principal"),_=D(require("@zondax/ledger-icp"));function ve(n,e){if(n.byteLength!==e.byteLength)return!1;let t=new Uint8Array(n),r=new Uint8Array(e);for(let i=0;i<t.length;i++)if(t[i]!==r[i])return!1;return!0}var Ne=n=>[...new Uint8Array(n)].map(e=>e.toString(16).padStart(2,"0")).join(""),w=class{static fromRaw(e){return new w(e)}static fromDer(e){return new w(this.derDecode(e))}static derEncode(e){if(e.byteLength!==w.RAW_KEY_LENGTH){let r=e.byteLength;throw new TypeError(`secp256k1 public key must be ${w.RAW_KEY_LENGTH} bytes long (is ${r})`)}return Uint8Array.from([...w.DER_PREFIX,...new Uint8Array(e)]).buffer}static derDecode(e){let t=w.DER_PREFIX.length+w.RAW_KEY_LENGTH;if(e.byteLength!==t){let i=e.byteLength;throw new TypeError(`secp256k1 DER-encoded public key must be ${t} bytes long (is ${i})`)}let r=e.slice(0,w.DER_PREFIX.length);if(!ve(this.derEncode(r),e))throw new TypeError(`secp256k1 DER-encoded public key is invalid. A valid secp256k1 DER-encoded public key must have the following prefix: ${w.DER_PREFIX}`);return r}constructor(e){this.rawKey=e,this.derKey=w.derEncode(e)}toDer(){return this.derKey}toRaw(){return this.rawKey}toHex(){let e=Ne(this.toRaw());if(!e.match("^[0-9a-fA-F]+$"))throw new Error(`${e} is not a hex string.`);if(e.length<130||e.length>150)throw new Error("The key must be >= 130 characters and <= 150 characters.");return e}},E=w;E.RAW_KEY_LENGTH=65,E.DER_PREFIX=Uint8Array.from([48,86,48,16,6,7,42,134,72,206,61,2,1,6,5,43,129,4,0,10,3,66,0]);var $=D(require("@ledgerhq/hw-transport-webhid")),B=D(require("@ledgerhq/hw-transport-node-hid-noevents")),Z=D(require("node-fetch"));global.fetch=Z.default;function Se(n){return K.Cbor.encode({content:n})}var S=class extends K.SignIdentity{constructor(t,r){super();this.derivePath=t;this._publicKey=r;this._neuronStakeFlag=!1}static async create(t="m/44'/223'/0'/0/0"){let[r,i]=await this._connect();try{let c=await this._fetchPublicKeyFromDevice(r,t);return new this(t,c)}finally{i.close()}}static async _connect(){async function t(){if(await $.default.isSupported())return $.default.create();if(await B.default.isSupported())return B.default.create();throw Error()}try{let r=await t();return[new _.default(r),r]}catch(r){throw r.id&&r.id=="NoDeviceFound"?"No Ledger device found. Is the wallet connected and unlocked?":r.message&&r.message.includes("cannot open device with path")?"Cannot connect to Ledger device. Please close all other wallet applications (e.g. Ledger Live) and try again.":`Cannot connect to Ledger Wallet. Either you have other wallet applications open (e.g. Ledger Live), or your browser doesn't support WebHID, which is necessary to communicate with your Ledger hardware wallet.
|
|
3
|
+
|
|
4
|
+
Supported browsers:
|
|
5
|
+
* Chrome (Desktop) v89+
|
|
6
|
+
* Edge v89+
|
|
7
|
+
* Opera v76+
|
|
8
|
+
|
|
9
|
+
Error: ${r}`}}static async _fetchPublicKeyFromDevice(t,r){let i=await t.getAddressAndPubKey(r);if(i.returnCode==28161)throw"Please open the Internet Computer app on your wallet and try again.";if(i.returnCode==_.LedgerError.TransactionRejected)throw"Ledger Wallet is locked. Unlock it and try again.";if(i.returnCode==65535)throw"Unable to fetch the public key. Please try again.";let c=i.principalText,o=E.fromRaw(new Uint8Array(i.publicKey));if(c!==z.Principal.selfAuthenticating(new Uint8Array(o.toDer())).toText())throw new Error("Principal returned by device does not match public key.");return o}async showAddressAndPubKeyOnDevice(){this._executeWithApp(async t=>{await t.showAddressAndPubKey(this.derivePath)})}async getVersion(){return this._executeWithApp(async t=>{let r=await t.getVersion();return{major:r.major,minor:r.minor,patch:r.patch}})}getPublicKey(){return this._publicKey}async sign(t){return await this._executeWithApp(async r=>{let i=await r.sign(this.derivePath,Buffer.from(t),this._neuronStakeFlag?1:0);this._neuronStakeFlag=!1;let c=i.signatureRS;if(!c)throw new Error(`A ledger error happened during signature:
|
|
10
|
+
Code: ${i.returnCode}
|
|
11
|
+
Message: ${JSON.stringify(i.errorMessage)}
|
|
12
|
+
`);if(c?.byteLength!==64)throw new Error(`Signature must be 64 bytes long (is ${c.length})`);return Ae(c)})}flagUpcomingStakeNeuron(){this._neuronStakeFlag=!0}async transformRequest(t){let{body:r,...i}=t,c=await this.sign(Se(r));return{...i,body:{content:r,sender_pubkey:this._publicKey.toDer(),sender_sig:c}}}async _executeWithApp(t){let[r,i]=await S._connect();try{let c=await S._fetchPublicKeyFromDevice(r,this.derivePath);if(JSON.stringify(c)!==JSON.stringify(this._publicKey))throw new Error("Found unexpected public key. Are you sure you're using the right wallet?");return await t(r)}finally{i.close()}}};function Ae(n){return n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength)}var T=require("@dfinity/utils");var H=require("@dfinity/sns"),h="2.2.1",Q=1e4,V=[H.SnsNeuronPermissionType.NEURON_PERMISSION_TYPE_VOTE,H.SnsNeuronPermissionType.NEURON_PERMISSION_TYPE_SUBMIT_PROPOSAL];var ee=require("commander"),ne=require("@dfinity/agent"),I=async({identity:n,minVersion:e})=>{if(!(n instanceof S))return;let{major:t,minor:r,patch:i}=await n.getVersion(),c=`${t}.${r}.${i}`;if((0,T.smallerVersion)({currentVersion:c,minVersion:e}))throw new Error(`Ledger app version ${c} is too old. Please update to ${e} or newer.`)},F=async({identity:n,version:e})=>{if(!(n instanceof S))return!1;let{major:t,minor:r,patch:i}=await n.getVersion(),c=`${t}.${r}.${i}`;return(0,T.smallerVersion)({currentVersion:c,minVersion:e})},te=n=>n.fullNeuron!==void 0?n.fullNeuron.cachedNeuronStake+n.fullNeuron.maturityE8sEquivalent>BigInt(Q):!1;async function re(n){if(n<0||n>255)throw new ee.InvalidArgumentError("Principal path must be between 0 and 255 inclusive.");return S.create(`m/44'/223'/0'/0/${n}`)}async function oe(n,e){let t=new URL(e).host!="ic0.app",r=new ne.HttpAgent({host:e,identity:n});return t&&await r.fetchRootKey(),r}var Ce=n=>n.reduce((e,t)=>`${e}${t.toString(16).padStart(2,"0")}`,""),ie=n=>Ce(Array.from(n)),De=n=>{let e=[];for(let t=0;t<n.length;t+=2){let r=n.substring(t,t+2),i=parseInt(r,16);e.push(i)}return e},ae=n=>({id:(0,T.arrayOfNumberToUint8Array)(De(n))}),se=()=>BigInt(Date.now())*BigInt(1e6);var ue=require("@dfinity/ledger");function f(n){let e=parseInt(n,10);if(isNaN(e))throw new b.InvalidArgumentError("Not a number.");return e}function de(n){let e=parseInt(n,10);if(isNaN(e))throw new b.InvalidArgumentError("Not a number.");if(e<0||e>100)throw new b.InvalidArgumentError("Not a percentage. Try a number between 0 and 100.");return e}function le(n){if(!["true","false"].includes(n))throw new b.InvalidArgumentError("Not a boolean. Try 'true' or 'false'.");return n!=="false"}function m(n){try{return BigInt(n)}catch(e){throw new b.InvalidArgumentError(e.toString())}}function y(n){try{return ce.Principal.fromText(n)}catch(e){throw new b.InvalidArgumentError(e.toString())}}function C(n){try{return ae(n)}catch(e){throw new b.InvalidArgumentError(e.toString())}}function R(n){try{return k.TokenAmount.fromE8s({amount:m(n),token:k.ICPToken})}catch(e){throw new b.InvalidArgumentError(e.toString())}}function G(n){try{return k.AccountIdentifier.fromHex(n)}catch(e){throw new b.InvalidArgumentError(e.toString())}}function W(n){try{return(0,ue.decodeIcrcAccount)(n)}catch(e){throw new b.InvalidArgumentError(e.toString())}}var pe=require("@dfinity/principal");var O=require("@dfinity/agent"),A=require("@dfinity/sns"),q=require("@dfinity/utils"),x=require("@dfinity/ledger"),P=D(require("chalk")),qn=require("node-window-polyfill/register"),j=D(require("node-fetch"));global.fetch=j.default;window.fetch=j.default;var L=new a.Command,v=console.log,Y=60,me=60*Y,X=24*me,ge=365*X+6*me,U=pe.Principal.fromText("ryjl3-tyaaa-aaaaa-aaaba-cai");async function l(){let n=f(L.opts().principal);return re(n)}async function u(n){let e=L.opts().network;return oe(n,e)}async function Ee(n){let e=await l(),r=await A.SnsGovernanceCanister.create({agent:await u(new O.AnonymousIdentity),canisterId:n}).listNeurons({certified:!0,principal:e.getPrincipal()});r.length>0?r.forEach(i=>{let c=(0,q.fromNullable)(i.id);v(c!==void 0?`Neuron ID: ${ie(c.id)}`:"Neuron ID: N/A")}):p("No neurons found.")}async function ke({neuronId:n,principal:e,canisterId:t}){let r=await l();await A.SnsGovernanceCanister.create({agent:await u(r),canisterId:t}).addNeuronPermissions({neuronId:n,principal:e,permissions:V}),p()}async function xe({neuronId:n,principal:e,canisterId:t}){let r=await l();await A.SnsGovernanceCanister.create({agent:await u(r),canisterId:t}).removeNeuronPermissions({neuronId:n,principal:e,permissions:V}),p()}async function Oe({neuronId:n,canisterId:e}){let t=await l();await A.SnsGovernanceCanister.create({agent:await u(t),canisterId:e}).startDissolving(n),p()}async function Te({neuronId:n,canisterId:e}){let t=await l();await A.SnsGovernanceCanister.create({agent:await u(t),canisterId:e}).stopDissolving(n),p()}async function Re({neuronId:n,canisterId:e,amount:t,to:r}){let i=await l();await A.SnsGovernanceCanister.create({agent:await u(i),canisterId:e}).disburse({neuronId:n,amount:t?.toE8s(),toAccount:r}),p()}async function Ke({neuronId:n,canisterId:e,percentageToStake:t}){let r=await l();await A.SnsGovernanceCanister.create({agent:await u(r),canisterId:e}).stakeMaturity({neuronId:n,percentageToStake:t}),p()}async function _e(n=U){let t={owner:(await l()).getPrincipal()},i=await x.IcrcLedgerCanister.create({agent:await u(new O.AnonymousIdentity),canisterId:n??U}).balance(t);p(`Account ${(0,x.encodeIcrcAccount)(t)} has balance ${i} e8s`)}async function Le({canisterId:n=U,amount:e,to:t}){let r=await l(),i=x.IcrcLedgerCanister.create({agent:await u(r),canisterId:n}),o=await x.IcrcLedgerCanister.create({agent:await u(new O.AnonymousIdentity),canisterId:n}).transactionFee({});await i.transfer({to:{owner:t.owner,subaccount:(0,q.toNullable)(t.subaccount)},amount:e.toE8s(),fee:o,created_at_time:se()}),p()}async function qe(){let n=await l(),e=s.AccountIdentifier.fromPrincipal({principal:n.getPrincipal()}),r=await s.LedgerCanister.create({agent:await u(new O.AnonymousIdentity),hardwareWallet:!0}).accountBalance({accountIdentifier:e});p(`Account ${e.toHex()} has balance ${r} e8s`)}async function $e(n,e){let t=await l(),i=await s.LedgerCanister.create({agent:await u(t),hardwareWallet:!0}).transfer({to:n,amount:e.toE8s(),memo:BigInt(0)});p(`Transaction completed at block height ${i}.`)}async function Be(n){let e=await l(),t=s.AccountIdentifier.fromPrincipal({principal:e.getPrincipal()}),r=e.getPublicKey();v(P.default.bold("Principal: ")+e.getPrincipal()),v(P.default.bold(`Address (${e.derivePath}): `)+t.toHex()),v(P.default.bold("Public key: ")+r.toHex()),n&&(v("Displaying the principal and the address on the device..."),await e.showAddressAndPubKeyOnDevice())}async function He(n){let e=await l(),t=s.LedgerCanister.create({agent:await u(e)}),r=s.GovernanceCanister.create({agent:await u(new O.AnonymousIdentity),hardwareWallet:!0});e.flagUpcomingStakeNeuron();try{let i=await r.stakeNeuron({stake:n.toE8s(),principal:e.getPrincipal(),ledgerCanister:t});p(`Staked neuron with ID: ${i}`)}catch(i){i instanceof s.InsufficientAmountError?M(`Cannot stake less than ${i.minimumAmount} e8s`):i instanceof s.InsufficientFundsError?M(`Your account has insufficient funds (${i.balance} e8s)`):console.log(i)}}async function Ve(n,e,t,r,i){let c=await l(),o=s.GovernanceCanister.create({agent:await u(c)}),g=e*ge+t*X+r*Y+i;await o.increaseDissolveDelay({neuronId:n,additionalDissolveDelaySeconds:g}),p()}async function Fe(n,e,t,r,i){let c=await l();await I({identity:c,minVersion:h});let o=s.GovernanceCanister.create({agent:await u(c)}),g=e*ge+t*X+r*Y+i;await o.setDissolveDelay({neuronId:n,dissolveDelaySeconds:Math.floor(Date.now()/1e3)+g}),p()}async function Ge(n,e,t){let r=await l();await s.GovernanceCanister.create({agent:await u(r),hardwareWallet:!0}).disburse({neuronId:BigInt(n),toAccountId:e,amount:t}),p()}async function We(n,e){let t=await l();await I({identity:t,minVersion:h}),await s.GovernanceCanister.create({agent:await u(t)}).splitNeuron({neuronId:BigInt(n),amount:e}),p()}async function Ue(n,e,t){let r=await l();t!==void 0&&await I({identity:r,minVersion:h});let c=await s.GovernanceCanister.create({agent:await u(r),hardwareWallet:t===void 0&&await F({identity:r,version:h})}).spawnNeuron({neuronId:BigInt(n),newController:e,percentageToSpawn:t});p(`Spawned neuron with ID ${c}`)}async function Me(n,e){let t=await l();await I({identity:t,minVersion:h}),await s.GovernanceCanister.create({agent:await u(t)}).stakeMaturity({neuronId:BigInt(n),percentageToStake:e}),p()}async function je(n,e){let t=await l();await I({identity:t,minVersion:h}),await s.GovernanceCanister.create({agent:await u(t)}).autoStakeMaturity({neuronId:BigInt(n),autoStake:e}),p()}async function Ye(n){let e=await l();await s.GovernanceCanister.create({agent:await u(e)}).startDissolving(n),p()}async function Xe(n){let e=await l();await s.GovernanceCanister.create({agent:await u(e)}).stopDissolving(n),p()}async function Je(n){let e=await l();await I({identity:e,minVersion:h}),await s.GovernanceCanister.create({agent:await u(e),hardwareWallet:!0}).joinCommunityFund(n),p()}async function ze(n){let e=await l();await I({identity:e,minVersion:h}),await s.GovernanceCanister.create({agent:await u(e),hardwareWallet:!0}).leaveCommunityFund(n),p()}async function Ze(n,e){let t=await l();await s.GovernanceCanister.create({agent:await u(t),hardwareWallet:!0}).addHotkey({neuronId:BigInt(n),principal:e}),p()}async function Qe(n,e){let t=await l();await s.GovernanceCanister.create({agent:await u(t),hardwareWallet:!0}).removeHotkey({neuronId:BigInt(n),principal:e}),p()}async function en(n=!1){let e=await l(),r=await s.GovernanceCanister.create({agent:await u(e),hardwareWallet:await F({identity:e,version:"2.0.0"})}).listNeurons({certified:!0});r.length>0?r.filter(i=>n||te(i)).forEach(i=>{v(`Neuron ID: ${i.neuronId}`)}):p("No neurons found.")}async function nn(n,e){let t=await l();await I({identity:t,minVersion:h}),await s.GovernanceCanister.create({agent:await u(t)}).mergeNeurons({targetNeuronId:e,sourceNeuronId:n}),p()}async function tn(n){let e=await l();await I({identity:e,minVersion:h}),await s.GovernanceCanister.create({agent:await u(e)}).setNodeProviderAccount(n.toHex()),p()}async function rn(){let n=await l(),t=n.getPublicKey().toHex(),i=await(await s.GenesisTokenCanister.create({agent:await u(n)})).claimNeurons({hexPubKey:t});p(`Successfully claimed the following neurons: ${i}`)}async function d(n){try{await n()}catch(e){M(e)}}function p(n){v(n?`${P.default.green(P.default.bold("OK"))}: ${n}`:`${P.default.green(P.default.bold("OK"))}`)}function M(n){let e=n instanceof s.GovernanceError?n.detail.error_message:n instanceof Error?n.message:n;v(`${P.default.bold(P.default.red("Error:"))} ${e}`)}async function on(){let n=new a.Command("icrc").description("Commands for managing ICRC ledger.").addCommand(new a.Command("balance").description("Get the balance of the main account on the ICRC wallet.").option("--canister-id <canister-id>","Canister ID (defaults to ICP Ledger)",y).action(o=>d(()=>_e(o.canisterId)))).addCommand(new a.Command("transfer").description("Send tokens from the ICRC wallet to another account.").option("--canister-id <canister-id>","Canister ID (defaults to ICP Ledger)",y).requiredOption("--to <account-identifier>","ICRC Account",W).requiredOption("--amount <amount>","Amount to transfer in e8s",R).action(({to:o,amount:g,canisterId:N})=>{d(()=>Le({to:o,amount:g,canisterId:N}))})),e=new a.Command("neuron").description("Commands for managing sns neurons.").addCommand(new a.Command("list").requiredOption("--canister-id <canister-id>","Canister ID",y).action(o=>d(()=>Ee(o.canisterId)))).addCommand(new a.Command("add-hotkey").requiredOption("--canister-id <canister-id>","Canister ID",y).requiredOption("--principal <principal>","Principal",y).requiredOption("--neuron-id <neuron-id>","Neuron ID",C).action(({canisterId:o,principal:g,neuronId:N})=>d(()=>ke({canisterId:o,principal:g,neuronId:N})))).addCommand(new a.Command("remove-hotkey").requiredOption("--canister-id <canister-id>","Canister ID",y).requiredOption("--principal <principal>","Principal",y).requiredOption("--neuron-id <neuron-id>","Neuron ID",C).action(({canisterId:o,principal:g,neuronId:N})=>d(()=>xe({canisterId:o,principal:g,neuronId:N})))).addCommand(new a.Command("start-dissolving").requiredOption("--canister-id <canister-id>","Canister ID",y).requiredOption("--neuron-id <neuron-id>","Neuron ID",C).action(({canisterId:o,neuronId:g})=>d(()=>Oe({canisterId:o,neuronId:g})))).addCommand(new a.Command("stop-dissolving").requiredOption("--canister-id <canister-id>","Canister ID",y).requiredOption("--neuron-id <neuron-id>","Neuron ID",C).action(({canisterId:o,neuronId:g})=>d(()=>Te({canisterId:o,neuronId:g})))).addCommand(new a.Command("stake-maturity").requiredOption("--canister-id <canister-id>","Canister ID",y).requiredOption("--neuron-id <neuron-id>","Neuron ID",C).option("--percentage <percentage>","Percentage of the maturity to stake (defaults to 100)",de).action(({canisterId:o,neuronId:g,percentage:N})=>d(()=>Ke({canisterId:o,neuronId:g,percentageToStake:N})))).addCommand(new a.Command("disburse").requiredOption("--canister-id <canister-id>","Canister ID",y).requiredOption("--neuron-id <neuron-id>","Neuron ID",C).option("--to <account-identifier>","ICRC Account (defaults to controller's main account)",W).option("--amount <amount>","Amount to disburse in e8s (empty to disburse all)",R).action(({neuronId:o,to:g,amount:N,canisterId:ye})=>{d(()=>Re({neuronId:o,to:g,amount:N,canisterId:ye}))})),t=new a.Command("sns").description("Commands for managing SNS.").addCommand(e),r=new a.Command("neuron").description("Commands for managing neurons.").showSuggestionAfterError().addCommand(new a.Command("stake").requiredOption("--amount <amount>","Amount to stake in e8s.",R).action(o=>d(()=>He(o.amount)))).addCommand(new a.Command("increase-dissolve-delay").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).option("--years <years>","Number of years",f).option("--days <days>","Number of days",f).option("--minutes <minutes>","Number of minutes",f).option("--seconds <seconds>","Number of seconds",f).action(o=>d(()=>Ve(o.neuronId,o.years||0,o.days||0,o.minutes||0,o.seconds||0)))).addCommand(new a.Command("set-dissolve-delay").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).option("--years <years>","Number of years",f).option("--days <days>","Number of days",f).option("--minutes <minutes>","Number of minutes",f).option("--seconds <seconds>","Number of seconds",f).action(o=>d(()=>Fe(o.neuronId,o.years||0,o.days||0,o.minutes||0,o.seconds||0)))).addCommand(new a.Command("disburse").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).option("--to <account-identifier>").option("--amount <amount>","Amount to disburse in e8s (empty to disburse all)",m).action(o=>{d(()=>Ge(o.neuronId,o.to,o.amount))})).addCommand(new a.Command("split").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).option("--amount <amount>","Amount split into a new neuron in e8s",m).action(o=>{d(()=>We(o.neuronId,o.amount))})).addCommand(new a.Command("spawn").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).option("--controller <new-controller>","Controller",y).option("--percentage-to-spawn <percentage>","Percentage of maturity to spawn",f).action(o=>{d(()=>Ue(o.neuronId,o.controller,o.percentageToSpawn))})).addCommand(new a.Command("stake-maturity").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).option("--percentage-to-stake <percentage>","Percentage of maturity to stake",f).action(o=>{d(()=>Me(o.neuronId,o.percentageToStake))})).addCommand(new a.Command("enable-auto-stake-maturity").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).requiredOption("--enable-auto-stake <enable>","Should auto stake maturity be enabled",le).action(o=>{d(()=>je(o.neuronId,o.enableAutoStake))})).addCommand(new a.Command("start-dissolving").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).action(o=>{d(()=>Ye(o.neuronId))})).addCommand(new a.Command("stop-dissolving").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).action(o=>{d(()=>Xe(o.neuronId))})).addCommand(new a.Command("join-community-fund").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).action(o=>{d(()=>Je(o.neuronId))})).addCommand(new a.Command("leave-community-fund").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).action(o=>{d(()=>ze(o.neuronId))})).addCommand(new a.Command("list").option("--show-zero-stake","Show neurons with zero stake and maturity").action(o=>d(()=>en(o.showZeroStake)))).addCommand(new a.Command("add-hotkey").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).requiredOption("--principal <principal>","Principal",y).action(o=>d(()=>Ze(o.neuronId,o.principal)))).addCommand(new a.Command("merge-neurons").requiredOption("--source-neuron-id <source-neuron-id>","Neuron ID",m).requiredOption("--target-neuron-id <target-neuron-id>","Neuron ID",m).action(o=>d(()=>nn(o.sourceNeuronId,o.targetNeuronId)))).addCommand(new a.Command("remove-hotkey").requiredOption("--neuron-id <neuron-id>","Neuron ID",m).requiredOption("--principal <principal>","Principal",y).action(o=>d(()=>Qe(o.neuronId,o.principal)))).addCommand(new a.Command("claim").description("Claim the caller's GTC neurons.").action(o=>d(()=>rn()))),i=new a.Command("icp").description("Commands for managing ICP.").showSuggestionAfterError().addCommand(new a.Command("balance").description("Fetch current balance.").action(()=>{d(qe)})).addCommand(new a.Command("transfer").requiredOption("--to <account-identifier>","Account identifier to transfer to.",G).requiredOption("--amount <amount>","Amount to transfer in e8s.",R).action(o=>d(()=>$e(o.to,o.amount)))),c=new a.Command("node-provider").description("Commands for managing node providers.").showSuggestionAfterError().addCommand(new a.Command("set-node-provider-account").requiredOption("--account <account>","Account ID",G).action(o=>d(()=>tn(o.account))));L.description("A CLI for the Ledger hardware wallet.").enablePositionalOptions().showSuggestionAfterError().addOption(new a.Option("--network <network>","The IC network to talk to.").default("https://ic0.app").env("IC_NETWORK")).addOption(new a.Option("--principal <principal>",`The derivation path to use for the principal.
|
|
13
|
+
(e.g. --principal 123 will result in a derivation path of m/44'/223'/0'/0/123)
|
|
14
|
+
Must be >= 0 && <= 255`).default(0)).addCommand(new a.Command("info").option("-n --no-show-on-device").description("Show the wallet's principal, address, and balance.").action(o=>{d(()=>Be(o.showOnDevice))})).addCommand(i).addCommand(r).addCommand(t).addCommand(n).addCommand(c),await L.parseAsync(process.argv)}on();
|
package/package.json
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dfinity/hardware-wallet-cli",
|
|
3
|
-
"version": "0.2.2",
|
|
4
3
|
"description": "A CLI to interact with the Internet Computer App on Ledger Nano S/X devices.",
|
|
5
|
-
"main": "./
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist/index.js",
|
|
7
|
+
"README.md",
|
|
8
|
+
"LICENSE"
|
|
9
|
+
],
|
|
6
10
|
"scripts": {
|
|
7
11
|
"format": "prettier --write .",
|
|
8
12
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
-
"build": "
|
|
13
|
+
"build": "node rmdir.mjs && node esbuild.mjs",
|
|
10
14
|
"prepack": "npm run build",
|
|
11
|
-
"clean": "
|
|
15
|
+
"clean": "npm run build",
|
|
12
16
|
"refresh": "rm -rf ./node_modules ./package-lock.json && npm install",
|
|
13
|
-
"execute": "ts-node ./index.ts",
|
|
14
|
-
"update:
|
|
17
|
+
"execute": "ts-node ./src/index.ts",
|
|
18
|
+
"update:next": "npm update @dfinity/nns @dfinity/sns @dfinity/utils",
|
|
19
|
+
"update:agent": "npm rm @dfinity/agent @dfinity/principal && npm i @dfinity/agent @dfinity/principal"
|
|
20
|
+
},
|
|
21
|
+
"engineStrict": true,
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">= 18.13.0"
|
|
15
24
|
},
|
|
16
25
|
"repository": {
|
|
17
26
|
"type": "git",
|
|
@@ -24,24 +33,35 @@
|
|
|
24
33
|
},
|
|
25
34
|
"homepage": "https://github.com/dfinity/hardware-wallet-cli#readme",
|
|
26
35
|
"dependencies": {
|
|
27
|
-
"@dfinity/agent": "^0.
|
|
28
|
-
"@dfinity/
|
|
36
|
+
"@dfinity/agent": "^0.15.2",
|
|
37
|
+
"@dfinity/ledger": "next",
|
|
38
|
+
"@dfinity/nns": "next",
|
|
39
|
+
"@dfinity/principal": "^0.15.2",
|
|
40
|
+
"@dfinity/sns": "next",
|
|
41
|
+
"@dfinity/utils": "next",
|
|
29
42
|
"@ledgerhq/hw-transport-node-hid-noevents": "^6.3.0",
|
|
30
43
|
"@ledgerhq/hw-transport-webhid": "^6.27.1",
|
|
31
44
|
"@zondax/ledger-icp": "^0.6.0",
|
|
45
|
+
"buffer": "^6.0.3",
|
|
32
46
|
"chalk": "^4.1.2",
|
|
33
47
|
"commander": "^9.0.0",
|
|
34
48
|
"node-fetch": "^2.6.1",
|
|
35
49
|
"node-window-polyfill": "^1.0.2"
|
|
36
50
|
},
|
|
37
51
|
"devDependencies": {
|
|
52
|
+
"@esbuild-plugins/node-resolve": "^0.2.0",
|
|
38
53
|
"@types/google-protobuf": "^3.15.6",
|
|
39
54
|
"@types/node": "^17.0.16",
|
|
40
55
|
"@types/node-hid": "^1.3.1",
|
|
56
|
+
"esbuild": "^0.17.4",
|
|
41
57
|
"prettier": "^2.6.2",
|
|
42
|
-
"ts-node": "^10.
|
|
58
|
+
"ts-node": "^10.9.1"
|
|
43
59
|
},
|
|
44
60
|
"bin": {
|
|
45
|
-
"ic-hardware-wallet": "./
|
|
46
|
-
}
|
|
47
|
-
|
|
61
|
+
"ic-hardware-wallet": "./dist/index.js"
|
|
62
|
+
},
|
|
63
|
+
"overrides": {
|
|
64
|
+
"semver": "^7.5.3"
|
|
65
|
+
},
|
|
66
|
+
"version": "0.3.0-next-2023-08-28"
|
|
67
|
+
}
|
package/.github/CODEOWNERS
DELETED
package/.prettierignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
build
|
package/build/index.js
DELETED
|
@@ -1,401 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
-
};
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
/**
|
|
8
|
-
* A CLI tool for testing the Ledger hardware wallet integration.
|
|
9
|
-
*/
|
|
10
|
-
const commander_1 = require("commander");
|
|
11
|
-
const identity_1 = require("./src/ledger/identity");
|
|
12
|
-
const nns_1 = require("@dfinity/nns");
|
|
13
|
-
const principal_1 = require("@dfinity/principal");
|
|
14
|
-
const agent_1 = require("@dfinity/agent");
|
|
15
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
16
|
-
// Add polyfill for `window` for `TransportWebHID` checks to work.
|
|
17
|
-
require("node-window-polyfill/register");
|
|
18
|
-
// Add polyfill for `window.fetch` for agent-js to work.
|
|
19
|
-
// @ts-ignore (no types are available)
|
|
20
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
21
|
-
global.fetch = node_fetch_1.default;
|
|
22
|
-
window.fetch = node_fetch_1.default;
|
|
23
|
-
const program = new commander_1.Command();
|
|
24
|
-
const log = console.log;
|
|
25
|
-
const SECONDS_PER_MINUTE = 60;
|
|
26
|
-
const SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
|
|
27
|
-
const SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
|
|
28
|
-
const SECONDS_PER_YEAR = 365 * SECONDS_PER_DAY + 6 * SECONDS_PER_HOUR;
|
|
29
|
-
async function getAgent(identity) {
|
|
30
|
-
const network = program.opts().network;
|
|
31
|
-
// Only fetch the rootkey if the network isn't mainnet.
|
|
32
|
-
const fetchRootKey = new URL(network).host == "ic0.app" ? false : true;
|
|
33
|
-
const agent = new agent_1.HttpAgent({
|
|
34
|
-
host: program.opts().network,
|
|
35
|
-
identity: identity,
|
|
36
|
-
});
|
|
37
|
-
if (fetchRootKey) {
|
|
38
|
-
await agent.fetchRootKey();
|
|
39
|
-
}
|
|
40
|
-
return agent;
|
|
41
|
-
}
|
|
42
|
-
async function getLedgerIdentity() {
|
|
43
|
-
const principalPath = tryParseInt(program.opts().principal);
|
|
44
|
-
if (principalPath < 0 || principalPath > 255) {
|
|
45
|
-
throw new commander_1.InvalidArgumentError("Principal path must be between 0 and 255 inclusive.");
|
|
46
|
-
}
|
|
47
|
-
return identity_1.LedgerIdentity.create(`m/44'/223'/0'/0/${principalPath}`);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Fetches the balance of the main account on the wallet.
|
|
51
|
-
*/
|
|
52
|
-
async function getBalance() {
|
|
53
|
-
const identity = await getLedgerIdentity();
|
|
54
|
-
const accountIdentifier = nns_1.AccountIdentifier.fromPrincipal({
|
|
55
|
-
principal: identity.getPrincipal(),
|
|
56
|
-
});
|
|
57
|
-
const ledger = nns_1.LedgerCanister.create({
|
|
58
|
-
agent: await getAgent(new agent_1.AnonymousIdentity()),
|
|
59
|
-
hardwareWallet: true,
|
|
60
|
-
});
|
|
61
|
-
const balance = await ledger.accountBalance({
|
|
62
|
-
accountIdentifier: accountIdentifier,
|
|
63
|
-
});
|
|
64
|
-
ok(`Account ${accountIdentifier.toHex()} has balance ${balance.toE8s()} e8s`);
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Send ICP to another address.
|
|
68
|
-
*
|
|
69
|
-
* @param to The account identifier in hex.
|
|
70
|
-
* @param amount Amount to send in e8s.
|
|
71
|
-
*/
|
|
72
|
-
async function sendICP(to, amount) {
|
|
73
|
-
const identity = await getLedgerIdentity();
|
|
74
|
-
const ledger = nns_1.LedgerCanister.create({
|
|
75
|
-
agent: await getAgent(identity),
|
|
76
|
-
hardwareWallet: true,
|
|
77
|
-
});
|
|
78
|
-
const blockHeight = await ledger.transfer({
|
|
79
|
-
to: to,
|
|
80
|
-
amount: amount,
|
|
81
|
-
memo: BigInt(0),
|
|
82
|
-
});
|
|
83
|
-
ok(`Transaction completed at block height ${blockHeight}.`);
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Shows the principal and account idenifier on the terminal and on the wallet's screen.
|
|
87
|
-
*/
|
|
88
|
-
async function showInfo(showOnDevice) {
|
|
89
|
-
const identity = await getLedgerIdentity();
|
|
90
|
-
const accountIdentifier = nns_1.AccountIdentifier.fromPrincipal({
|
|
91
|
-
principal: identity.getPrincipal(),
|
|
92
|
-
});
|
|
93
|
-
const publicKey = identity.getPublicKey();
|
|
94
|
-
log(chalk_1.default.bold(`Principal: `) + identity.getPrincipal());
|
|
95
|
-
log(chalk_1.default.bold(`Address (${identity.derivePath}): `) + accountIdentifier.toHex());
|
|
96
|
-
log(chalk_1.default.bold('Public key: ') + publicKey.toHex());
|
|
97
|
-
if (showOnDevice) {
|
|
98
|
-
log("Displaying the principal and the address on the device...");
|
|
99
|
-
await identity.showAddressAndPubKeyOnDevice();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Stakes a new neuron.
|
|
104
|
-
*
|
|
105
|
-
* @param amount Amount to stake in e8s.
|
|
106
|
-
*/
|
|
107
|
-
async function stakeNeuron(stake) {
|
|
108
|
-
const identity = await getLedgerIdentity();
|
|
109
|
-
const ledger = nns_1.LedgerCanister.create({
|
|
110
|
-
agent: await getAgent(identity),
|
|
111
|
-
});
|
|
112
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
113
|
-
agent: await getAgent(new agent_1.AnonymousIdentity()),
|
|
114
|
-
hardwareWallet: true,
|
|
115
|
-
});
|
|
116
|
-
// Flag that an upcoming stake neuron transaction is coming to distinguish
|
|
117
|
-
// it from a "send ICP" transaction on the device.
|
|
118
|
-
identity.flagUpcomingStakeNeuron();
|
|
119
|
-
try {
|
|
120
|
-
const stakedNeuronId = await governance.stakeNeuron({
|
|
121
|
-
stake: stake,
|
|
122
|
-
principal: identity.getPrincipal(),
|
|
123
|
-
ledgerCanister: ledger,
|
|
124
|
-
});
|
|
125
|
-
ok(`Staked neuron with ID: ${stakedNeuronId}`);
|
|
126
|
-
}
|
|
127
|
-
catch (error) {
|
|
128
|
-
if (error instanceof nns_1.InsufficientAmountError) {
|
|
129
|
-
err(`Cannot stake less than ${error.minimumAmount.toE8s()} e8s`);
|
|
130
|
-
}
|
|
131
|
-
else if (error instanceof nns_1.InsufficientFundsError) {
|
|
132
|
-
err(`Your account has insufficient funds (${error.balance.toE8s()} e8s)`);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
console.log(error);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
async function increaseDissolveDelay(neuronId, years, days, minutes, seconds) {
|
|
140
|
-
const identity = await getLedgerIdentity();
|
|
141
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
142
|
-
agent: await getAgent(identity),
|
|
143
|
-
hardwareWallet: true,
|
|
144
|
-
});
|
|
145
|
-
const additionalDissolveDelaySeconds = years * SECONDS_PER_YEAR +
|
|
146
|
-
days * SECONDS_PER_DAY +
|
|
147
|
-
minutes * SECONDS_PER_MINUTE +
|
|
148
|
-
seconds;
|
|
149
|
-
await governance.increaseDissolveDelay({
|
|
150
|
-
neuronId: neuronId,
|
|
151
|
-
additionalDissolveDelaySeconds: additionalDissolveDelaySeconds,
|
|
152
|
-
});
|
|
153
|
-
ok();
|
|
154
|
-
}
|
|
155
|
-
async function disburseNeuron(neuronId, to, amount) {
|
|
156
|
-
const identity = await getLedgerIdentity();
|
|
157
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
158
|
-
agent: await getAgent(identity),
|
|
159
|
-
hardwareWallet: true,
|
|
160
|
-
});
|
|
161
|
-
await governance.disburse({
|
|
162
|
-
neuronId: BigInt(neuronId),
|
|
163
|
-
toAccountId: to,
|
|
164
|
-
amount: amount,
|
|
165
|
-
});
|
|
166
|
-
ok();
|
|
167
|
-
}
|
|
168
|
-
async function spawnNeuron(neuronId, controller) {
|
|
169
|
-
const identity = await getLedgerIdentity();
|
|
170
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
171
|
-
agent: await getAgent(identity),
|
|
172
|
-
hardwareWallet: true,
|
|
173
|
-
});
|
|
174
|
-
const spawnedNeuronId = await governance.spawnNeuron({
|
|
175
|
-
neuronId: BigInt(neuronId),
|
|
176
|
-
newController: controller,
|
|
177
|
-
});
|
|
178
|
-
ok(`Spawned neuron with ID ${spawnedNeuronId}`);
|
|
179
|
-
}
|
|
180
|
-
async function startDissolving(neuronId) {
|
|
181
|
-
const identity = await getLedgerIdentity();
|
|
182
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
183
|
-
agent: await getAgent(identity),
|
|
184
|
-
hardwareWallet: true,
|
|
185
|
-
});
|
|
186
|
-
await governance.startDissolving(neuronId);
|
|
187
|
-
ok();
|
|
188
|
-
}
|
|
189
|
-
async function stopDissolving(neuronId) {
|
|
190
|
-
const identity = await getLedgerIdentity();
|
|
191
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
192
|
-
agent: await getAgent(identity),
|
|
193
|
-
hardwareWallet: true,
|
|
194
|
-
});
|
|
195
|
-
await governance.stopDissolving(neuronId);
|
|
196
|
-
ok();
|
|
197
|
-
}
|
|
198
|
-
async function addHotkey(neuronId, principal) {
|
|
199
|
-
const identity = await getLedgerIdentity();
|
|
200
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
201
|
-
agent: await getAgent(identity),
|
|
202
|
-
hardwareWallet: true,
|
|
203
|
-
});
|
|
204
|
-
await governance.addHotkey({
|
|
205
|
-
neuronId: BigInt(neuronId),
|
|
206
|
-
principal: principal,
|
|
207
|
-
});
|
|
208
|
-
ok();
|
|
209
|
-
}
|
|
210
|
-
async function removeHotkey(neuronId, principal) {
|
|
211
|
-
const identity = await getLedgerIdentity();
|
|
212
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
213
|
-
agent: await getAgent(identity),
|
|
214
|
-
hardwareWallet: true,
|
|
215
|
-
});
|
|
216
|
-
await governance.removeHotkey({
|
|
217
|
-
neuronId: BigInt(neuronId),
|
|
218
|
-
principal: principal,
|
|
219
|
-
});
|
|
220
|
-
ok();
|
|
221
|
-
}
|
|
222
|
-
async function listNeurons() {
|
|
223
|
-
const identity = await getLedgerIdentity();
|
|
224
|
-
const governance = nns_1.GovernanceCanister.create({
|
|
225
|
-
agent: await getAgent(identity),
|
|
226
|
-
hardwareWallet: true,
|
|
227
|
-
});
|
|
228
|
-
// We filter neurons with no ICP, as they'll be garbage collected by the governance canister.
|
|
229
|
-
const neurons = await governance.listNeurons({
|
|
230
|
-
certified: true,
|
|
231
|
-
});
|
|
232
|
-
if (neurons.length > 0) {
|
|
233
|
-
neurons.forEach((n) => {
|
|
234
|
-
log(`Neuron ID: ${n.neuronId}`);
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
ok("No neurons found.");
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Fetches the balance of the main account on the wallet.
|
|
243
|
-
*/
|
|
244
|
-
async function claimNeurons() {
|
|
245
|
-
const identity = await getLedgerIdentity();
|
|
246
|
-
const publicKey = identity.getPublicKey();
|
|
247
|
-
const hexPubKey = publicKey.toHex();
|
|
248
|
-
const governance = await nns_1.GenesisTokenCanister.create({
|
|
249
|
-
agent: await getAgent(identity),
|
|
250
|
-
});
|
|
251
|
-
const claimedNeuronIds = await governance.claimNeurons({
|
|
252
|
-
hexPubKey,
|
|
253
|
-
});
|
|
254
|
-
ok(`Successfully claimed the following neurons: ${claimedNeuronIds}`);
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Runs a function with a try/catch block.
|
|
258
|
-
*/
|
|
259
|
-
async function run(f) {
|
|
260
|
-
try {
|
|
261
|
-
await f();
|
|
262
|
-
}
|
|
263
|
-
catch (error) {
|
|
264
|
-
err(error);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
function ok(message) {
|
|
268
|
-
if (message) {
|
|
269
|
-
log(`${chalk_1.default.green(chalk_1.default.bold("OK"))}: ${message}`);
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
272
|
-
log(`${chalk_1.default.green(chalk_1.default.bold("OK"))}`);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
function err(error) {
|
|
276
|
-
const message = error instanceof nns_1.GovernanceError
|
|
277
|
-
? error.detail.error_message
|
|
278
|
-
: error instanceof Error
|
|
279
|
-
? error.message
|
|
280
|
-
: error;
|
|
281
|
-
log(`${chalk_1.default.bold(chalk_1.default.red("Error:"))} ${message}`);
|
|
282
|
-
}
|
|
283
|
-
function tryParseInt(value) {
|
|
284
|
-
const parsedValue = parseInt(value, 10);
|
|
285
|
-
if (isNaN(parsedValue)) {
|
|
286
|
-
throw new commander_1.InvalidArgumentError("Not a number.");
|
|
287
|
-
}
|
|
288
|
-
return parsedValue;
|
|
289
|
-
}
|
|
290
|
-
function tryParseBigInt(value) {
|
|
291
|
-
try {
|
|
292
|
-
return BigInt(value);
|
|
293
|
-
}
|
|
294
|
-
catch (err) {
|
|
295
|
-
throw new commander_1.InvalidArgumentError(err.toString());
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
function tryParsePrincipal(value) {
|
|
299
|
-
try {
|
|
300
|
-
return principal_1.Principal.fromText(value);
|
|
301
|
-
}
|
|
302
|
-
catch (err) {
|
|
303
|
-
throw new commander_1.InvalidArgumentError(err.toString());
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
function tryParseE8s(e8s) {
|
|
307
|
-
try {
|
|
308
|
-
return nns_1.ICP.fromE8s(tryParseBigInt(e8s));
|
|
309
|
-
}
|
|
310
|
-
catch (err) {
|
|
311
|
-
throw new commander_1.InvalidArgumentError(err.toString());
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
function tryParseAccountIdentifier(accountIdentifier) {
|
|
315
|
-
try {
|
|
316
|
-
return nns_1.AccountIdentifier.fromHex(accountIdentifier);
|
|
317
|
-
}
|
|
318
|
-
catch (err) {
|
|
319
|
-
throw new commander_1.InvalidArgumentError(err.toString());
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
async function main() {
|
|
323
|
-
const neuron = new commander_1.Command("neuron")
|
|
324
|
-
.description("Commands for managing neurons.")
|
|
325
|
-
.showSuggestionAfterError()
|
|
326
|
-
.addCommand(new commander_1.Command("stake")
|
|
327
|
-
.requiredOption("--amount <amount>", "Amount to stake in e8s.", tryParseE8s)
|
|
328
|
-
.action((args) => run(() => stakeNeuron(args.amount))))
|
|
329
|
-
.addCommand(new commander_1.Command("increase-dissolve-delay")
|
|
330
|
-
.requiredOption("--neuron-id <neuron-id>", "Neuron ID", tryParseBigInt)
|
|
331
|
-
.option("--years <years>", "Number of years", tryParseInt)
|
|
332
|
-
.option("--days <days>", "Number of days", tryParseInt)
|
|
333
|
-
.option("--minutes <minutes>", "Number of minutes", tryParseInt)
|
|
334
|
-
.option("--seconds <seconds>", "Number of seconds", tryParseInt)
|
|
335
|
-
.action((args) => run(() => increaseDissolveDelay(args.neuronId, args.years || 0, args.days || 0, args.minutes || 0, args.seconds || 0))))
|
|
336
|
-
.addCommand(new commander_1.Command("disburse")
|
|
337
|
-
.requiredOption("--neuron-id <neuron-id>", "Neuron ID", tryParseBigInt)
|
|
338
|
-
.option("--to <account-identifier>")
|
|
339
|
-
.option("--amount <amount>", "Amount to disburse (empty to disburse all)", tryParseBigInt)
|
|
340
|
-
.action((args) => {
|
|
341
|
-
run(() => disburseNeuron(args.neuronId, args.to, args.amount));
|
|
342
|
-
}))
|
|
343
|
-
.addCommand(new commander_1.Command("spawn")
|
|
344
|
-
.requiredOption("--neuron-id <neuron-id>", "Neuron ID", tryParseBigInt)
|
|
345
|
-
.option("--controller <new-controller>", "Controller", tryParsePrincipal)
|
|
346
|
-
.action((args) => {
|
|
347
|
-
run(() => spawnNeuron(args.neuronId, args.controller));
|
|
348
|
-
}))
|
|
349
|
-
.addCommand(new commander_1.Command("start-dissolving")
|
|
350
|
-
.requiredOption("--neuron-id <neuron-id>", "Neuron ID", tryParseBigInt)
|
|
351
|
-
.action((args) => {
|
|
352
|
-
run(() => startDissolving(args.neuronId));
|
|
353
|
-
}))
|
|
354
|
-
.addCommand(new commander_1.Command("stop-dissolving")
|
|
355
|
-
.requiredOption("--neuron-id <neuron-id>", "Neuron ID", tryParseBigInt)
|
|
356
|
-
.action((args) => {
|
|
357
|
-
run(() => stopDissolving(args.neuronId));
|
|
358
|
-
}))
|
|
359
|
-
.addCommand(new commander_1.Command("list").action(() => run(listNeurons)))
|
|
360
|
-
.addCommand(new commander_1.Command("add-hotkey")
|
|
361
|
-
.requiredOption("--neuron-id <neuron-id>", "Neuron ID", tryParseBigInt)
|
|
362
|
-
.requiredOption("--principal <principal>", "Principal", tryParsePrincipal)
|
|
363
|
-
.action((args) => run(() => addHotkey(args.neuronId, args.principal))))
|
|
364
|
-
.addCommand(new commander_1.Command("remove-hotkey")
|
|
365
|
-
.requiredOption("--neuron-id <neuron-id>", "Neuron ID", tryParseBigInt)
|
|
366
|
-
.requiredOption("--principal <principal>", "Principal", tryParsePrincipal)
|
|
367
|
-
.action((args) => run(() => removeHotkey(args.neuronId, args.principal))))
|
|
368
|
-
.addCommand(new commander_1.Command("claim")
|
|
369
|
-
.description("Claim the caller's GTC neurons.")
|
|
370
|
-
.action((args) => run(() => claimNeurons())));
|
|
371
|
-
const icp = new commander_1.Command("icp")
|
|
372
|
-
.description("Commands for managing ICP.")
|
|
373
|
-
.showSuggestionAfterError()
|
|
374
|
-
.addCommand(new commander_1.Command("balance")
|
|
375
|
-
.description("Fetch current balance.")
|
|
376
|
-
.action(() => {
|
|
377
|
-
run(getBalance);
|
|
378
|
-
}))
|
|
379
|
-
.addCommand(new commander_1.Command("transfer")
|
|
380
|
-
.requiredOption("--to <account-identifier>", "Account identifier to transfer to.", tryParseAccountIdentifier)
|
|
381
|
-
.requiredOption("--amount <amount>", "Amount to transfer in e8s.", tryParseE8s)
|
|
382
|
-
.action((args) => run(() => sendICP(args.to, args.amount))));
|
|
383
|
-
program
|
|
384
|
-
.description("A CLI for the Ledger hardware wallet.")
|
|
385
|
-
.enablePositionalOptions()
|
|
386
|
-
.showSuggestionAfterError()
|
|
387
|
-
.addOption(new commander_1.Option("--network <network>", "The IC network to talk to.")
|
|
388
|
-
.default("https://ic0.app")
|
|
389
|
-
.env("IC_NETWORK"))
|
|
390
|
-
.addOption(new commander_1.Option("--principal <principal>", "The derivation path to use for the principal.\n(e.g. --principal 123 will result in a derivation path of m/44'/223'/0'/0/123)\nMust be >= 0 && <= 255").default(0))
|
|
391
|
-
.addCommand(new commander_1.Command("info")
|
|
392
|
-
.option("-n --no-show-on-device")
|
|
393
|
-
.description("Show the wallet's principal, address, and balance.")
|
|
394
|
-
.action((args) => {
|
|
395
|
-
run(() => showInfo(args.showOnDevice));
|
|
396
|
-
}))
|
|
397
|
-
.addCommand(icp)
|
|
398
|
-
.addCommand(neuron);
|
|
399
|
-
await program.parseAsync(process.argv);
|
|
400
|
-
}
|
|
401
|
-
main();
|