MPC
MPC Wallet stands for "Multi-Party Computation" Wallet, a technology designed to improve the security and user convenience of cryptocurrency wallets. It operates by distributing keys and performing encryption tasks jointly by multiple participants. This offers several advantages:
-
In MPC wallets, the private key is divided into multiple pieces and stored in a distributed manner, making it impossible to recover the original private key with only one piece. Even if one key piece is leaked or lost, it can still be restored, preventing the risk of losing the entire asset due to the leak or loss of a single key.
-
It is resistant to hacking or insider threats since it does not rely on a central server. Additionally, it operates on a distributed network, eliminating the need for a single trusted point.
-
It can simplify complex key management procedures like mnemonics, improving user experience.
Wallet Creation
This diagram shows the overall flow required to call the MPC Key generation on the client side. The MPC Key returned in the key generation request enables transactions for the user's wallet.
The devicePassword used in the request is used to encrypt the key piece. The encpvstr received in the successful response of the key creation/recovery API call represents the encrypted KeyShare. The encryptDevicePassword is encrypted and returned by WaaS, forming a pair with the distributed key piece. Even if the client knows the plaintext of the devicePassword, it cannot be decrypted.
The encryptDevicePassword, encpv, and wid returned during MPC Key creation/recovery must be safely stored on the client side.
Key Recovery
If KeyShare is lost or damaged, the MPC Key can be recovered. In case of recovery, a new wallet is not created; rather, it is necessary to recover the KeyShare as it becomes unusable if lost or damaged.
With each recovery, the wid value increases by 1, and only the final wid value can be queried when calling the wallet inquiry API.
Additionally, encpvstr and encryptDevicePassword form a pair, and the client must securely store wid, encpvstr, and encryptDevicePassword.
Below is a sample code to help understand the Wallet create/recover process.
- Typescript
- Python
- Go
- Java
// mpc.ts - WAAS Wallet Create/Recover API Example
import axios from 'axios';
import qs from 'qs';
import { emailLogin } from './login'; // (2)
import { createSecureChannel, encrypt } from './secureChannel'; // (1)
/*
This example assumes normal operation and does not handle errors separately.
Error and exception handling should be applied during implementation.
Example written to build ts to js and run the dist file by configuring package.json.
Refer to the script in package.json.
// ``` json
"scripts": {
"start": "tsc | node dist/index.js",
},
// ```
*/
const WAAS_BASE_URL: string = 'https://dev-api.abcwaas.com';
// Not a mandatory function. Utility function.
function getBaseURL(): string {
const waas_base_url: string = process.env.WAAS_BASE_URL || WAAS_BASE_URL;
return waas_base_url;
}
type getWalletResult = {
uid: string;
wid: number;
sid: string;
pvencstr: string;
encryptDevicePassword: string;
};
async function getWallet(
email: string,
encryptedDevicePassword: string,
channelID: string,
accesssToken: string,
): Promise<getWalletResult> {
/*
Creates a unique MPC wallet for the user.
The user will own one unique wallet, and if a wallet already exists, the existing wallet will be restored.
devicePassword refers to the password for the Key Share of the wallet being created or restored.
GetWalletResult example:
>>> {
"uid": "d5b440b8-469b-4e16-8978-d78b73a09c4e",
"wid": 6,
"sid": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"pvencstr": "0x1234567890abcdef",
"encryptDevicePassword": "sEbZRmmOrvmMI83XugEzEVwRpwkBBCeXb4jMq1f8Wao="
}
Args:
email (str): User email
encrypted_device_password (str): devicePassword encrypted with Secure Channel
channel_id (str): Secure channel ID
access_token (str): The wallet user's JWT token
Returns:
GetWalletResult: The user's MPC wallet information
Raises:
HTTPError: If the wallet creation request fails
*/
try {
const urlStr = `${getBaseURL()}/wapi/v2/mpc/wallets`;
const data = qs.stringify({
email: email,
devicePassword: encryptedDevicePassword,
});
const response = await axios.post(urlStr, data, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Bearer ${accesssToken}`,
'Secure-Channel': channelID,
},
});
const wallet: getWalletResult = response.data;
return wallet;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(
`fail to getWallet. stataus code: ${
error.status
}, data: ${JSON.stringify(error.response?.data)}`,
);
}
throw new Error(`fail to getWallet`);
}
}
type walletAccount = {
id: string;
sid: string;
ethAddress: string;
icon: string;
name: string;
signer: string;
pubkey: string;
};
type walletInfo = {
_id: string;
uid: string;
wid: number;
email: string;
accounts: walletAccount[];
favorites: string[];
autoconfirms: string[];
twoFactorEnabled: boolean;
twoFactorResetRetryCount: number;
twoFactorRetryFreezeEndTime: number;
twoFactorFreezeEndTime: number;
};
async function getWalletInfo(accessToken: string): Promise<walletInfo> {
/*
Retrieves the user's MPC wallet.
Args:
access_token (str): The wallet user's JWT token.
WalletInfo example:
>>> {
"_id": "657bdc790b67b600128a865f",
"uid": "d5b440b8-469b-4e16-8978-d78b73a09c4e",
"wid": 6,
"email": "test_0@myabcwallet.com",
"accounts": [
{
"id": "0",
"sid": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"ethAddress": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4Hs....",
"name": "Account 1",
"signer": "mpc",
"pubkey": "0x025c5d89f60eba1b8fc5c2bd2fa28eefe48f4c950815acd7...."
}
],
"favorites": [],
"autoconfirms": [],
"twoFactorEnabled": false,
"twoFactorResetRetryCount": 0,
"twoFactorRetryFreezeEndTime": 0,
"twoFactorFreezeEndTime": 0
}
*/
try {
const urlStr = `${getBaseURL()}/wapi/v2/mpc/wallets/info`;
const response = await axios.get(urlStr, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const walletInfoRes: walletInfo = response.data;
return walletInfoRes;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(
`fail to get walletinfo. status code: ${
error.response?.status
}, data: ${JSON.stringify(error.response?.data)}`,
);
}
throw new Error(`fail to get walletinfo.`);
}
}
export async function mpcScenario() {
const email: string = 'email@email.com'; // User email
const password: string = 'password'; // User password
const clientID: string = 'client id'; // Client ID
const clientSecret: string = 'client secret'; // Client Secret
// Creating Secure Channel
const secureChannelRes = await createSecureChannel();
// The password needs to be encrypted with the Secure Channel.
const encryptedPassword = encrypt(secureChannelRes, password);
// Client ID / Client Secret
const auth = Buffer.from(`${clientID}:${clientSecret}`).toString('base64'); // (3)
// Login
const loginResult = await emailLogin(
email,
encryptedPassword,
secureChannelRes.ChannelID,
auth,
);
// JWT token is generated upon success
console.log(`access token : ${loginResult.accessToken}`);
const devicePassword = 'password'; // (4)
const encryptedDevicePassword = encrypt(secureChannelRes, devicePassword);
const wallet = await getWallet(
email,
encryptedDevicePassword,
secureChannelRes.ChannelID,
loginResult.accessToken,
);
console.log(`wallet uid: ${wallet.uid}`);
console.log(`wallet wid: ${wallet.wid}`);
console.log(`wallet sid: ${wallet.sid}`);
const walletInfo = await getWalletInfo(loginResult.accessToken);
console.log(`wallet uid: ${walletInfo.uid}`);
console.log(`wallet wid: ${walletInfo.wid}`);
console.log(`wallet sid: ${walletInfo.accounts[0].sid}`);
}
- 🙋 Getting Started > Secure Channel
- 🙋 Getting Started > Login
- 🙋 You need Client ID / Client Secret. The Client ID and Client Secret must be base64 encoded.
- 🙋 devicePassword is used for key shard encryption. Secure Channel encryption is required.
"""mpc.py - WAAS Wallet Create/Recover API Example"""
import base64
import os
from typing import TypedDict, List
import requests
import securechannel # (1)
import login # (2)
WAAS_BASE_URL = "https://dev-api.abcwaas.com"
WalletAccount = TypedDict(
"WalletAccount",
{
"id": str,
"sid": str,
"ethAddress": str,
"icon": str,
"name": str,
"signer": str,
"pubkey": str,
},
)
WalletInfo = TypedDict(
"WalletInfo",
{
"_id": str,
"uid": str,
"wid": int,
"email": str,
"accounts": List[WalletAccount],
"favorites": List,
"autoconfirms": List,
"twoFactorEnabled": bool,
"twoFactorResetRetryCount": int,
"twoFactorRetryFreezeEndTime": int,
"twoFactorFreezeEndTime": int,
},
)
GetWalletResult = TypedDict(
"GetWalletResult",
{
"uid": str,
"wid": int,
"sid": str,
"pvencstr": str,
"encryptDevicePassword": str,
},
)
def get_wallet_info(access_token: str) -> WalletInfo:
"""
Retrieves the user's MPC wallet.
Args:
access_token (str): The wallet user's JWT token.
WalletInfo example:
>>> {
"_id": "657bdc790b67b600128a865f",
"uid": "d5b440b8-469b-4e16-8978-d78b73a09c4e",
"wid": 6,
"email": "test_0@myabcwallet.com",
"accounts": [
{
"id": "0",
"sid": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"ethAddress": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4Hs....",
"name": "Account 1",
"signer": "mpc",
"pubkey": "0x025c5d89f60eba1b8fc5c2bd2fa28eefe48f4c950815acd7...."
}
],
"favorites": [],
"autoconfirms": [],
"twoFactorEnabled": false,
"twoFactorResetRetryCount": 0,
"twoFactorRetryFreezeEndTime": 0,
"twoFactorFreezeEndTime": 0
}
"""
waas_base_url = os.getenv("WAAS_BASE_URL", WAAS_BASE_URL)
r = requests.get(
url=f"{waas_base_url}/wapi/v2/mpc/wallets/info",
headers={"Authorization": f"Bearer {access_token}"},
)
r.raise_for_status()
return r.json()
def get_wallet(
email: str, encrypted_device_password: str, channel_id: str, access_token: str
) -> GetWalletResult:
"""
Creates a unique MPC wallet for the user.
The user will own one unique wallet, and if a wallet already exists, the existing wallet will be restored.
devicePassword refers to the password for the Key Share of the wallet being created or restored.
GetWalletResult example:
>>> {
"uid": "d5b440b8-469b-4e16-8978-d78b73a09c4e",
"wid": 6,
"sid": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"pvencstr": "0x1234567890abcdef",
"encryptDevicePassword": "sEbZRmmOrvmMI83XugEzEVwRpwkBBCeXb4jMq1f8Wao="
}
Args:
email (str): User email
encrypted_device_password (str): devicePassword encrypted with Secure Channel
channel_id (str): Secure channel ID
access_token (str): The wallet user's JWT token
Returns:
GetWalletResult: The user's MPC wallet information
Raises:
HTTPError: If the wallet creation request fails
"""
waas_base_url = os.getenv("WAAS_BASE_URL", WAAS_BASE_URL)
r = requests.post(
url=f"{waas_base_url}/wapi/v2/mpc/wallets",
headers={
"Secure-Channel": channel_id,
"Authorization": f"Bearer {access_token}",
},
data={"email": email, "devicePassword": encrypted_device_password},
)
return r.json()
def main():
email = "email" # User email
password = "password" # User password
client_id = "Client ID" # Client ID
client_secret = "Client Secret" # Client Secret
# Create Secure Channel
secure_channel = securechannel.create_secure_channel()
# needs to be encrypted with Secure Channel
encrypted_password = securechannel.encrypt(secure_channel, password)
# Client ID / Client Secret
auth = base64.b64encode(f"{client_id}:{client_secret}".encode("utf-8")).decode(
"utf-8"
) # (3)
# Login
email_login_result = login.email_login(
email,
encrypted_password,
secure_channel["channel_id"],
auth,
)
# On success, jwt token is generated
print(f"access_token: {email_login_result['access_token']}")
device_password = "password" # (4)
encrypted_device_password = securechannel.encrypt(secure_channel, device_password)
wallet = get_wallet(
email,
encrypted_device_password,
secure_channel["channel_id"],
email_login_result["access_token"],
)
print(f"wallet uid: {wallet['uid']}")
print(f"wallet wid: {wallet['wid']}")
print(f"wallet sid: {wallet['sid']}")
wallet_info = get_wallet_info(email_login_result["access_token"])
print(f"wallet_info uid: {wallet_info['uid']}")
print(f"wallet_info wid: {wallet_info['wid']}")
print(f"wallet_info sid: {wallet_info['accounts'][0]['sid']}")
if __name__ == "__main__":
main()
- 🙋 Getting Started > Secure Channel
- 🙋 Getting Started > Login
- 🙋 You need Client ID / Client Secret. The Client ID and Client Secret must be base64 encoded.
- 🙋 devicePassword is used for key shard encryption. Secure Channel encryption is required.
// mpc.go - WAAS Wallet Create/Recover API Example
package mpc
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"os"
"strings"
securechannel "github.com/ahnlabio/waas-example.git/golang/secureChannel" // (1)
"github.com/ahnlabio/waas-example.git/golang/login" // (2)
)
/*
This example assumes normal operation and does not handle errors separately.
Error and exception handling should be applied during implementation.
*/
const WAAS_BASE_URL = "https://dev-api.abcwaas.com"
// Not a mandatory function. Utility function.
func getBaseURL() string {
waas_base_url, isExistEnv := os.LookupEnv("WAAS_BASE_URL")
if !isExistEnv {
waas_base_url = WAAS_BASE_URL
}
return waas_base_url
}
type GetWalletResult struct {
UID string `json:"uid"`
WID int `json:"wid"`
SID string `json:"sid"`
Pvencstr string `json:"pvencstr"`
EncryptDevicePassword string `json:"encryptDevicePassword"`
}
func GetWallet(email, encryptedDevicePassowrd, channelID, accessToken string) GetWalletResult {
/*
Creates a unique MPC wallet for the user.
The user will own one unique wallet, and if a wallet already exists, the existing wallet will be restored.
devicePassword refers to the password for the Key Share of the wallet being created or restored.
GetWalletResult example:
>>> {
"uid": "d5b440b8-469b-4e16-8978-d78b73a09c4e",
"wid": 6,
"sid": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"pvencstr": "0x1234567890abcdef",
"encryptDevicePassword": "sEbZRmmOrvmMI83XugEzEVwRpwkBBCeXb4jMq1f8Wao="
}
Args:
email (str): User email
encrypted_device_password (str): devicePassword encrypted with Secure Channel
channel_id (str): Secure channel ID
access_token (str): The wallet user's JWT token
Returns:
GetWalletResult: The user's MPC wallet information
Raises:
HTTPError: If the wallet creation request fails
*/
urlStr := fmt.Sprintf("%s/wapi/v2/mpc/wallets", getBaseURL())
data := url.Values{
"email": {email},
"devicePassword": {encryptedDevicePassowrd},
}
req, err := http.NewRequest("POST", urlStr, strings.NewReader(data.Encode()))
if err != nil {
log.Fatal("Failed to create request:", err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Secure-Channel", channelID)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal("Request failed:", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatalf("Request failed with status: %d", resp.StatusCode)
}
var result GetWalletResult
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
log.Fatalf("fail to decode result %v\n", err)
}
return result
}
type WalletAccount struct {
ID string `json:"id"`
SID string `json:"sid"`
ETHAddress string `json:"ethAddress"`
Icon string `json:"icon"`
Name string `json:"name"`
Signer string `json:"signer"`
PublicKey string `json:"pubkey"`
}
type WalletInfo struct {
ID string `json:"_id"`
UID string `json:"uid"`
WID int `json:"wid"`
Email string `json:"email"`
Accounts []WalletAccount `json:"accounts"`
Favorites []string `json:"favorites"`
Autoconfirms []string `json:"autoconfirms"`
TwoFactorEnabled bool `json:"twoFactorEnabled"`
TwoFactorResetRetryCount int `json:"twoFactorResetRetryCount"`
TwoFactorRetryFreezEndTime int `json:"twoFactorRetryFreezeEndTime"`
TwoFactorFreezeEndTime int `json:"twoFactorFreezeEndTime"`
}
func GetWalletInfo(accessToken string) WalletInfo {
/*
Retrieves the user's MPC wallet.
Args:
access_token (str): The wallet user's JWT token.
WalletInfo example:
>>> {
"_id": "657bdc790b67b600128a865f",
"uid": "d5b440b8-469b-4e16-8978-d78b73a09c4e",
"wid": 6,
"email": "test_0@myabcwallet.com",
"accounts": [
{
"id": "0",
"sid": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"ethAddress": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4Hs....",
"name": "Account 1",
"signer": "mpc",
"pubkey": "0x025c5d89f60eba1b8fc5c2bd2fa28eefe48f4c950815acd7...."
}
],
"favorites": [],
"autoconfirms": [],
"twoFactorEnabled": false,
"twoFactorResetRetryCount": 0,
"twoFactorRetryFreezeEndTime": 0,
"twoFactorFreezeEndTime": 0
}
*/
urlStr := fmt.Sprintf("%s/wapi/v2/mpc/wallets/info", getBaseURL())
req, err := http.NewRequest("GET", urlStr, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal(resp, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatalf("fail to get wallet info: %v\n", resp)
}
var result WalletInfo
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
log.Fatalf("fail to decode result %v\n", err)
}
return result
}
func MPCScenario() {
email := "email@email.com" // User email
password := "password" // User password
clientID := "Client ID" // Client ID
clientSecret := "Client Secret" // Client Secret
// Creating Secure Channel
secureChannelRes := securechannel.CreateSecureChannel()
// The password needs to be encrypted with the Secure Channel.
encryptedPassword := securechannel.Encrypt(secureChannelRes, password)
// Client ID / Client Secret
auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", clientID, clientSecret))) // (3)
// Login
emailLoginResult := login.EmailLogin(email, encryptedPassword, secureChannelRes.ChannelID, auth)
// JWT token is generated upon success
fmt.Printf("access token: %s\n", emailLoginResult.AccessToken)
devicePassword := "password" // (4)
encryptedDevicePassword := securechannel.Encrypt(secureChannelRes, devicePassword)
wallet := GetWallet(email, encryptedDevicePassword, secureChannelRes.ChannelID, emailLoginResult.AccessToken)
fmt.Printf("wallet uid: %s\n", wallet.UID)
fmt.Printf("wallet wid: %v\n", wallet.WID)
fmt.Printf("wallet sid: %s\n", wallet.SID)
walletInfo := GetWalletInfo(emailLoginResult.AccessToken)
fmt.Printf("wallet info uid: %s\n", walletInfo.UID)
fmt.Printf("wallet info wid: %v\n", walletInfo.WID)
fmt.Printf("wallet info sid: %s\n", walletInfo.Accounts[0].SID)
}
- 🙋 Getting Started > Secure Channel
- 🙋 Getting Started > Login
- 🙋 You need Client ID / Client Secret. The Client ID and Client Secret must be base64 encoded.
- 🙋 devicePassword is used for key shard encryption. Secure Channel encryption is required.
/* Mpc.java - WAAS wallet create/recover API example */
package io.myabcwallet;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
/* bcprov-jdk18on */
import org.bouncycastle.util.encoders.Base64;
import com.google.gson.Gson;
import io.myabcwallet.Login.EmailLoginResult;
public class Mpc {
public static String WAAS_BASE_URL = "https://dev-api.abcwaas.com";
class WalletAccount {
String id;
String sid;
String ethAddress;
String icon;
String name;
String signer;
String pubkey;
}
class WalletInfo {
String _id;
String uid;
int wid;
String email;
List<WalletAccount> accounts;
List<String> favorites;
List<String> autoconfirms;
boolean twoFactorEnabled;
int twoFactorResetRetryCount;
int twoFactorRetryFreezeEndTime;
int twoFactorFreezeEndTime;
}
class GetWalletResult {
String uid;
int wid;
String sid;
String pvencstr;
String encryptDevicePassword;
}
public <T> T build(Object object, Class<T> classOfT) throws Exception {
Gson gson = new Gson();
String json = gson.toJson(object);
return build(json, classOfT);
}
public <T> T build(String message, Class<T> classOfT) throws Exception {
Gson gson = new Gson();
return (T) gson.fromJson(message, classOfT);
}
public GetWalletResult getWallet(String email, String encDevicePassword, String channelId, String accessToken) throws Exception {
/*
Creates a unique MPC wallet for the user.
The user will own one unique wallet, and if a wallet already exists, the existing wallet will be restored.
devicePassword refers to the password for the Key Share of the wallet being created or restored.
GetWalletResult example:
>>> {
"uid": "d5b440b8-469b-4e16-8978-d78b73a09c4e",
"wid": 6,
"sid": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"pvencstr": "0x1234567890abcdef",
"encryptDevicePassword": "sEbZRmmOrvmMI83XugEzEVwRpwkBBCeXb4jMq1f8Wao="
}
Args:
email (str): User email
encrypted_device_password (str): devicePassword encrypted with Secure Channel
channel_id (str): Secure channel ID
access_token (str): The wallet user's JWT token
Returns:
GetWalletResult: The user's MPC wallet information
Raises:
HTTPError: If the wallet creation request fails
*/
URL url = new URL(WAAS_BASE_URL + "/wapi/v2/mpc/wallets");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader buffer = null;
try {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("email=" + email);
stringBuffer.append("&devicePassword=" + encDevicePassword);
byte[] postData = stringBuffer.toString().getBytes(StandardCharsets.UTF_8);
int postDataLength = postData.length;
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("charset", "utf-8");
connection.setRequestProperty("Secure-Channel", channelId);
connection.setRequestProperty("Authorization", "Bearer " + accessToken);
connection.setRequestProperty("Content-Length", Integer.toString(postDataLength));
DataOutputStream stream = new DataOutputStream(connection.getOutputStream());
stream.write(postData);
buffer = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
StringBuilder stringBuilder = new StringBuilder();
String line = null;
while ((line = buffer.readLine()) != null) {
stringBuilder.append(line);
}
String response = stringBuilder.toString();
int responseCode = connection.getResponseCode();
if(responseCode != 200) {
throw new Exception(String.format("get wallet failed: [%d][%s]", responseCode, response));
}
return build(response, GetWalletResult.class);
}
catch(Exception e) {
e.printStackTrace();
throw e;
}
finally {
if(buffer != null) buffer.close();
}
}
public WalletInfo getWalletInfo(String acessToken) throws Exception {
/*
Retrieves the user's MPC wallet.
Args:
access_token (str): The wallet user's JWT token.
WalletInfo example:
>>> {
"_id": "657bdc790b67b600128a865f",
"uid": "d5b440b8-469b-4e16-8978-d78b73a09c4e",
"wid": 6,
"email": "test_0@myabcwallet.com",
"accounts": [
{
"id": "0",
"sid": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"ethAddress": "0xbE616d5b24903efc58149f3c7511FeC2085c176e",
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4Hs....",
"name": "Account 1",
"signer": "mpc",
"pubkey": "0x025c5d89f60eba1b8fc5c2bd2fa28eefe48f4c950815acd7...."
}
],
"favorites": [],
"autoconfirms": [],
"twoFactorEnabled": false,
"twoFactorResetRetryCount": 0,
"twoFactorRetryFreezeEndTime": 0,
"twoFactorFreezeEndTime": 0
}
*/
URL url = new URL(WAAS_BASE_URL + "/wapi/v2/mpc/wallets/info");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader buffer = null;
try {
connection.setDoOutput(true);
connection.setRequestMethod("GET");
connection.setRequestProperty("charset", "utf-8");
connection.setRequestProperty("Authorization", "Bearer " + acessToken);
buffer = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
StringBuffer stringBuffer = new StringBuffer();
String line = null;
while ((line = buffer.readLine()) != null) {
stringBuffer.append(line);
}
String response = stringBuffer.toString();
int responseCode = connection.getResponseCode();
if(responseCode != 200) {
throw new Exception(String.format("get wallet info failed: [%d][%s]", responseCode, response));
}
return build(response, WalletInfo.class);
}
catch(Exception e) {
e.printStackTrace();
throw e;
}
finally {
if(buffer != null) buffer.close();
}
}
public static void main(String[] args) throws Exception {
String email = "test01@ahnlab.com"; // User email
String password = "0123456789"; // User password
String clientId = "Client ID"; // Client ID
String clientSecret = "Client Secret"; // Client Secret
// Creating Secure Channel
SecureChannel secureChannel = new SecureChannel();
secureChannel.create("plainText");
// The password needs to be encrypted with the Secure Channel.
String encryptedPassword = secureChannel.encrypt(password);
// Client ID / Client Secret
String auth = new String(Base64.encode((clientId + ":" + clientSecret).getBytes())); // (3)
// Login
Login login = new Login();
EmailLoginResult emailLoginResult = login.emailLogin(
email,
encryptedPassword,
secureChannel.getChannelId(),
auth
);
// JWT token is generated upon success
System.out.println("access_token: " + emailLoginResult.access_token);
String devicePassword = "password"; // (4)
String encDevicePassword = secureChannel.encrypt(devicePassword);
Mpc mpc = new Mpc();
GetWalletResult getWalletResult = mpc.getWallet(
email,
encDevicePassword,
secureChannel.getChannelId(),
emailLoginResult.access_token
);
System.out.println("wallet uid: " + getWalletResult.uid);
System.out.println("wallet wid: " + getWalletResult.wid);
System.out.println("wallet sid: " + getWalletResult.sid);
WalletInfo walletInfo = mpc.getWalletInfo(emailLoginResult.access_token);
System.out.println("wallet_info uid: " + walletInfo.uid);
System.out.println("wallet_info wid: " + walletInfo.wid);
System.out.println("wallet_info sid: " + walletInfo.accounts.get(0).sid);
}
}
- 🙋 Getting Started > Secure Channel
- 🙋 Getting Started > Login
- 🙋 You need Client ID / Client Secret. The Client ID and Client Secret must be base64 encoded.
- 🙋 devicePassword is used for key shard encryption. Secure Channel encryption is required.