- About Keychain
- Usage
- Operations
- steem_keychain
- requestHandshake
- requestEncodeMessage
- requestEncodeWithKeys
- requestVerifyKey
- requestSignBuffer
- requestAddAccountAuthority
- requestRemoveAccountAuthority
- requestAddKeyAuthority
- requestRemoveKeyAuthority
- requestBroadcast
- requestSignTx
- requestSignedCall
- requestPost
- requestVote
- requestCustomJson
- requestTransfer
- requestSendToken
- requestDelegation
- requestWitnessVote
- requestProxy
- requestPowerUp
- requestPowerDown
- requestCreateClaimedAccount
- requestCreateProposal
- requestRemoveProposal
- requestUpdateProposalVote
- requestAddAccount
- requestConversion
- requestRecurrentTransfer
- requestSwap
- steem_keychain
- requestCallback
Putting private keys directly into websites is not safe or secure, even ones run by reputable community members. Yet this is currently how nearly every Steem-based site or service currently works. On top of that, most Steem users likely use their master password which is even worse.
The Vessel desktop wallet software is a secure alternative, but it is too difficult to use for the majority of Steem users and does not easily interact with websites - which is Steem's primary use case.
On Ethereum, you never have to enter your private key into a website to use a dApp. You can just use a browser extension like Metamask, which dApp websites can interface with to securely store your keys and broadcast transactions to the blockchain.
Steem Keychain aims to bring the security and ease-of-use of Metamask to the Steem blockchain platform.
You can download and install the latest published version of the extension for the following browsers:
- Google Chrome (or Opera/Brave): on Chrome Store
- Export your keys from Steem keychain (in settings)
- Download this repository as zip
- Unzip the downloaded folder
- Right click on any existing extension > Manage my extensions.
- Activate developer mode.
- Click "Load Unpacked" and select the unzipped folder.
- Import your keys (use the same master password)
- Firefox: on Firefox Addon Store
The Steem Keychain extension includes the following features:
- Store an unlimited number of Steem account keys, encrypted with AES
- View balances, transaction history, voting power, and resource credits
- Send STEEM and SBD transfers, manage witness votes, and update SP delegation right from the extension
- Manage your Steem Engine tokens
- Power up or down
- Securely interact with Steem-based websites that have integrated with Steem Keychain
- Manage transaction confirmation preferences by account and by website
- Locks automatically on browser shutdown or manually using the lock button
Websites can currently request the Steem Keychain extension to perform the following functions / broadcast operations:
- Send a handshake to make sure the extension is installed
- Decrypt a message encrypted by a Steem account private key (commonly used for "logging in")
- Post a comment (top level or reply)
- Broadcast a vote
- Broadcast a custom JSON operation
- Send a transfer
- Send Steem Engine tokens
- Send Delegations
- Power up/down
- Vote for witnesses
- Create/Remove/Vote for proposals
- Create claimed accounts
- Sign Tx
An example of a web page that interacts with the extension is included in the "example" folder in the repo. You can test it by running a local HTTP server and going to http://localhost:1337/main.html in your browser.
cd example
python -m http.server 1337 //or any other method to run a static server
NOTE: On localhost, it will run on port 1337.
To login, you can encode a message from your backend and verify that the user can decode it using the requestVerifyKey method.
See an example in this project by @howo (@steempress witness):
Alternatively, you can use requestSignTx and verify the signature on your backend.
This npm module makes it easy to add Keychain support within the browser. It also includes helpful functions to check whether Keychain was used before. It was developed by @therealwolf (witness).
The Steem Keychain extension will inject a "steem_keychain" JavaScript into all web pages opened in the browser while the extension is running. You can therefore check if the current user has the extension installed using the following code:
Use the steem_keychain methods listed below to issue requests to the Steem blockchain.
This function is called to verify Keychain installation on a user's device
callbackfunction Confirms Keychain installation (has no parameters)
This function is called to verify that the user has a certain authority over an account, by requesting to decode a message
usernameString Steem account to perform the requestreceiverString Account that will decode the stringmessageString Message to be encryptedkeyString Type of key. Can be 'Posting','Active' or 'Memo'callbackrequestCallback Function that handles Keychain's response to the request
const keychain = window.steem_keychain;
const message = username + Date.now();
keychain.requestEncodeMessage(
username,
myUsername,
message,
'Memo',
(response) => {
if (response.success) {
const encodedMessage = response.result;
// Send message to a server where you can use your private key to decode it
}
},
);This function is called to allow encoding a message with multiple receivers. This is used in the case of multisig
usernameString Steem account to perform the requestpublicKeysArray<String> Key that can decode the stringmessageString Message to be encryptedkeyString Type of key. Can be 'Posting','Active' or 'Memo'callbackrequestCallback Function that handles Keychain's response to the request
const keychain = window.steem_keychain;
const message = username + Date.now();
keychain.requestEncodeMessage(
username,
[pubKey1, pubKey2],
message,
'Memo',
(response) => {
if (response.success) {
const encodedMessages = response.result;
// Send message to a server where you can use your private key to decode it
}
},
);This function is called to verify that the user has a certain authority over an account, by requesting to decode a message
accountString Steem account to perform the requestmessageString Message to be decoded by the accountkeyString Type of key. Can be 'Posting','Active' or 'Memo'callbackrequestCallback Function that handles Keychain's response to the request
const keychain = window.steem_keychain;
keychain.requestVerifyKey('faisalamin', encodedMessage, 'Posting', (response) => {
if (response.success === true) {
const decodedMessage = response.result;
}
});Requests a message to be signed with proper authority
accountString Steem account to perform the request. If null, user can choose the account from a dropdown (optional, defaultnull)messageString Message to be signed by the accountkeyString Type of key. Can be 'Posting','Active' or 'Memo'callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)titleString Override "Sign message" title (optional, defaultnull)
Requests to add account authority over another account. For more information about multisig, please read https://steempro.com/utopian-io/@stoodkev/how-to-set-up-and-use-multisignature-accounts-on-steem-blockchain
accountString Steem account to perform the requestauthorizedUsernameString Authorized accountroleString Type of authority. Can be 'Posting','Active' or 'Memo'weightnumber Weight of the authoritycallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Gives @faisalamin active authority with weight 2 to `account`
const keychain = window.steem_keychain;
keychain.requestAddAccountAuthority(
account,
'faisalamin',
'Active',
2,
(response) => {
console.log(response);
},
);Requests to remove an account authority over another account. For more information about multisig, please read https://steempro.com/utopian-io/@stoodkev/how-to-set-up-and-use-multisignature-accounts-on-steem-blockchain
accountString Steem account to perform the requestauthorizedUsernameString Account to lose authorityroleString Type of authority. Can be 'Posting','Active' or 'Memo'callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Removes @faisalamin's active authority from `account`
const keychain = window.steem_keychain;
keychain.requestRemoveAccountAuthority(
account,
'faisalamin',
'Active',
(response) => {
console.log(response);
},
);Requests to add a new key authority to an account. For more information about multisig, please read https://steempro.com/utopian-io/@stoodkev/how-to-set-up-and-use-multisignature-accounts-on-steem-blockchain
accountString Steem account to perform the requestauthorizedKeyString New public key to be associated with the accountroleString Type of authority. Can be 'Posting','Active' or 'Memo'weightnumber Weight of the key authoritycallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
const keychain = window.steem_keychain;
keychain.requestAddKeyAuthority(username, publicKey, 'Memo', 1, (response) => {
console.log(response);
});Requests to remove a key to an account. For more information about multisig, please read https://steempro.com/utopian-io/@stoodkev/how-to-set-up-and-use-multisignature-accounts-on-steem-blockchain
accountString Steem account to perform the requestauthorizedKeyString Key to be removed (public key).roleString Type of authority. Can be 'Posting','Active' or 'Memo'.callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
const keychain = window.steem_keychain;
keychain.requestRemoveKeyAuthority(username, publicKey, 'Memo', (response) => {
console.log(response);
});Generic broadcast request
accountString Steem account to perform the requestoperationsArray Array of operations to be broadcastedkeyString Type of key. Can be 'Posting','Active' or 'Memo'callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
const keychain = window.steem_keychain;
keychain.requestBroadcast(
'npfedwards',
[
[
'account_witness_vote',
{
account: 'npfedwards',
witness: 'faisalamin',
approve: true,
},
],
],
'Active',
(response) => {
console.log(response);
},
);Requests to sign a transaction with a given authority
accountString Steem account to perform the requesttxObject Unsigned transactionkeyString Type of key. Can be 'Posting','Active' or 'Memo'callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// This example would be done much easier with requestBroadcast
import dsteem from '@steempro/dsteem';
const client = new dsteem.Client(['https://api.steemit.com', 'https://api.justyy.co', 'https://api.steemitdev.com']);
const keychain = window.steem_keychain;
const props = await client.database.getDynamicGlobalProperties();
const headBlockNumber = props.head_block_number;
const headBlockId = props.head_block_id;
const expireTime = 600000;
const op = {
ref_block_num: headBlockNumber & 0xffff,
ref_block_prefix: Buffer.from(headBlockId, 'hex').readUInt32LE(4),
expiration: new Date(Date.now() + expireTime).toISOString(),
operations: [...] // Add operations here
};
keychain.requestSignTx(username, op, 'Posting', async (response) => {
if (!response.error) {
console.log(response.result);
await client.database.verifyAuthority(response.result);
await client.broadcast.send(response.result);
}
});Requests a signed call
accountString Steem account to perform the requestmethodString Method of the callparamsString Parameters of the callkeyString Type of key. Can be 'Posting','Active' or 'Memo'callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
Meta
- deprecated: This is deprecated.
Requests to broadcast a blog post/comment
accountString Steem account to perform the requesttitleString Title of the blog postbodyString Content of the blog postparent_permString Permlink of the parent post. Main tag for a root postparent_accountString Author of the parent post. Pass null for root postjson_metadataObject Parameters of the callpermlinkString Permlink of the blog postcomment_optionsObject Options attached to the blog post. Consult Steem documentation at https://developers.steem.io/apidefinitions/#broadcast_ops_comment_options to learn more about itcallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
const keychain = window.steem_keychain;
keychain.requestPost(
'faisalamin',
'Hello World!',
'## This is a blog post \
\
And this is some text',
'Blog',
null,
{ format: 'markdown', description: 'A blog post', tags: ['Blog'] },
'hello-world',
{
author: 'faisalamin',
permlink: 'hi',
max_accepted_payout: '100000.000 SBD',
percent_steem_dollars: 10000,
allow_votes: true,
allow_curation_rewards: true,
extensions: [
[
0,
{
beneficiaries: [
{ account: 'yabapmatt', weight: 1000 },
{ account: 'steemplus-pay', weight: 500 },
],
},
],
],
},
(response) => {
console.log(response);
},
);Requests a vote
accountString Steem account to perform the requestpermlinkString Permlink of the blog postauthorString Author of the blog postweightNumber Weight of the vote, comprised between -10,000 (-100%) and 10,000 (100%)callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Upvote with 50% weight
const keychain = window.steem_keychain;
keychain.requestVote(
'npfedwards',
'hello-world',
'faisalamin',
5000,
(response) => {
console.log(response);
},
);Requests a custom JSON broadcast
accountString Steem account to perform the request. If null, user can choose the account from a dropdown (optional, defaultnull)idString Type of custom_json to be broadcastedkeyString Type of key. Can be 'Posting','Active' or 'Memo'jsonString Stringified custom jsondisplay_msgString Message to display to explain to the user what this broadcast is aboutcallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
const keychain = window.steem_keychain;
keychain.requestCustomJson(
null,
'sm_market_rent',
'Active',
JSON.stringify({
items: ['9292cd44ccaef8b73a607949cc787f1679ede10b-93'],
currency: 'DEC',
days: 1,
}),
'Rent 1 card on Splinterlands',
(response) => {
console.log(response);
},
);Requests a transfer
accountString Steem account to perform the requesttoString Steem account to receive the transferamountString Amount to be transfered. Requires 3 decimals.memoString The memo will be automatically encrypted if starting by '#' and the memo key is available on Keychain. It will also overrule the account to be enforced, regardless of the 'enforce' parametercurrencyString 'STEEM' or 'SBD'callbackrequestCallback Function that handles Keychain's response to the requestenforceboolean If set to true, user cannot chose to make the transfer from another account (optional, defaultfalse)rpcString Override user's RPC settings (optional, defaultnull)
const keychain = window.steem_keychain;
keychain.requestTransfer(
username,
toUsername,
amount.toFixed(3),
'',
'STEEM',
(response) => {
console.log(response);
},
true,
);Requests a token transfer
accountString Steem account to perform the requesttoString Steem account to receive the transferamountString Amount to be transferred. Requires 3 decimals.memoString Memo attached to the transfercurrencyString Token to be sentcallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestSendToken(
username,
toUsername,
amount.toFixed(3),
memo,
'DEC',
(response) => {
console.log(response);
},
);
} else {
alert('You do not have steem keychain installed');
}Requests a delegation broadcast
usernameString Steem account to perform the request. If null, user can choose the account from a dropdown (optional, defaultnull)delegateeString Account to receive the delegationamountString Amount to be transfered. Requires 3 decimals for SP, 6 for VESTS.unitString SP or VESTScallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestDelegation(null, 'faisalamin', '1.000', 'SP', (response) => {
console.log(response);
});
} else {
alert('You do not have steem keychain installed');
}Requests a witness vote broadcast
usernameString Steem account to perform the request. If null, user can choose the account from a dropdown (optional, defaultnull)witnessString Account to receive the witness votevoteboolean Set to true to vote for the witness, false to unvotecallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Unvote our witness vote for @faisalamin
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestWitnessVote(null, 'faisalamin', false, (response) => {
console.log(response);
});
} else {
alert('You do not have steem keychain installed');
}Select an account as proxy
usernameString Steem account to perform the request. If null, user can choose the account from a dropdown (optional, defaultnull)proxyString Account to become the proxy. Empty string ('') to remove a proxycallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Let @faisalamin use our voting power in governance votes
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestProxy(null, 'faisalamin', (response) => {
console.log(response);
});
} else {
alert('You do not have steem keychain installed');
}// Remove voting proxy
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestProxy(null, '', (response) => {
console.log(response);
});
} else {
alert('You do not have steem keychain installed');
}Request a power up
usernameString Steem account to perform the requestrecipientString Account to receive the power upsteemString Amount of STEEM to be powered upcallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Power up 5 SP
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestPowerUp(username, username, '5.000', (response) => {
console.log(response);
});
} else {
alert('You do not have steem keychain installed');
}Request a power down
usernameString Steem account to perform the requeststeem_powerString Amount of STEEM to be powered downcallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Power down 5 SP
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestPowerDown(username, '5.000', (response) => {
console.log(response);
});
} else {
alert('You do not have steem keychain installed');
}Request the creation of an account using claimed tokens
usernameString Steem account to perform the requestnew_accountString New account to be createdownerobject owner authority objectactiveobject active authority objectpostingobject posting authority objectmemoString public memo keycallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
Request the creation of a DHF proposal
usernameString Steem account to perform the requestreceiverString Account receiving the funding if the proposal is votedsubjectString Title of the DAOpermlinkString Permlink to the proposal descriptiondaily_payString Daily amount to be received byreceiverstartString Starting dateendString Ending dateextensionsString Stringified Array of extensionscallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestCreateProposal(
'keychain',
'keychain',
'Steem Keychain development',
'steem-keychain-proposal-dhf-ran717',
'10.000',
'2022-03-22',
'2023-03-21',
JSON.stringify([]),
(response) => {
console.log(response);
},
);
} else {
alert('You do not have steem keychain installed');
}Request the removal of a DHF proposal
usernameString Steem account to perform the requestproposal_idsString Stringified Array of ids of the proposals to be removedextensionsString Stringified Array of extensionscallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestRemoveProposal(
username,
JSON.stringify([216]),
JSON.stringify([]),
(response) => {
console.log(response);
},
);
} else {
alert('You do not have steem keychain installed');
}Vote/Unvote a DHF proposal
usernameString Steem account to perform the requestproposal_idsString Stringified Array of Ids of the proposals to be votedapproveboolean Set to true to support the proposal, false to remove a voteextensionsString Stringified Array of extensionscallbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Approve a proposal
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestUpdateProposalVote(
username,
JSON.stringify([216]),
true,
JSON.stringify([]),
(response) => {
console.log(response);
},
);
} else {
alert('You do not have steem keychain installed');
}// Unapprove a proposal
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestUpdateProposalVote(
username,
JSON.stringify([216]),
false,
JSON.stringify([]),
(response) => {
console.log(response);
},
);
} else {
alert('You do not have steem keychain installed');
}Add a new account to Keychain
usernameString username of the account to be addedkeysObject private keys of the account : {active:'...',posting:'...',memo:'...'}. At least one must be specified. Alternatively, authorized accounts can be specified with @${username}.callbackrequestCallback Function that handles Keychain's response to the request
if (window.steem_keychain) {
const postingKey = '...';
const keychain = window.steem_keychain;
keychain.requestConversion(
username,
{
posting: postingKey,
},
(response) => {
console.log(response);
},
);
} else {
alert('You do not have steem keychain installed');
}Request currency conversion
usernameString Steem account to perform the requestamountString amount to be converted.collaterizedBoolean true to convert STEEM to SBD. false to convert SBD to STEEM.callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Convert 5 STEEM to SBD
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestConversion(username, '5.000', true, (response) => {
console.log(response);
});
} else {
alert('You do not have steem keychain installed');
}Request recurrent transfer
usernameString Steem account to perform the request (optional, defaultnull)toString Steem account receiving the transfers.amountString amount to be sent on each execution.currencyString STEEM or SBD on mainnet.memoString transfer memorecurrenceNumber How often will the payment be triggered (in hours) - minimum 24.executionsNumber The times the recurrent payment will be executed - minimum 2.callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Let's send @faisalamin 5 STEEM a day
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestConversion(
null,
'faisalamin',
'5.000',
'STEEM',
memo,
24,
7,
(response) => {
console.log(response);
},
);
} else {
alert('You do not have steem keychain installed');
}Request swap
usernameString Steem account to perform the request (optional, defaultnull)startTokenString Incoming tokenendTokenString Outgoing tokenamountnumber Amount of tokens to be swappedslippagenumber Max slippagestepsObject Steps returned by KeychainSDK.swaps.getEstimation(), of type IStep[]callbackrequestCallback Function that handles Keychain's response to the requestrpcString Override user's RPC settings (optional, defaultnull)
// Let's swap 5 STEEM to DEC
// Estimated steps can be obtained via KeychainSDK.swaps.getEstimation()
if (window.steem_keychain) {
const keychain = window.steem_keychain;
keychain.requestSwap(
'keychain',
'STEEM',
'DEC',
5,
1,
estimatedSteps,
(response) => {
console.log(response);
},
);
} else {
alert('You do not have steem keychain installed');
}Type: Function
responseObject Keychain's response to the request
