1.0.0 • Published 7 months ago

@onelabs/wallet v1.0.0

Weekly downloads
-
License
ISC
Repository
gitlab
Last release
7 months ago

TOC

One chain wallet js sdk

Full documents

Installation

For use in Node.js or a web application

npm install @onelabs/wallet --save

For use in a browser, without a build system

<!-- Development (un-minified) -->
<script src="https://unpkg.com/@onelabs/wallet@latest/lib/index.iife.js"></script>

<!-- Production (minified) -->
<script src="https://unpkg.com/@onelabs/wallett@latest/lib/index.iife.min.js"></script>

Testing

npm run test

Documentation and examples

Init

const {Connection, clusterApiUrl} = require("@onelabs/wallet");
//Or import {Connection, clusterApiUrl} from ("@onelabs/wallet");

const connection = new Connection(clusterApiUrl("devnet"),{});

Login and get ZkProofs

//Huione user
let user = {
    mobile:       "mobile number",
    mobilePrefix: "mobile prefix",
    merchantId:   "user merchant id",
    merchantKey:  "user merchant secretKey(RSA private key)",
};

let code = await connection.requestSmsCode(rsaEncrypt({
    merchantId:   user.merchantId,
    mobile:       user.mobile,
    mobilePrefix: user.mobilePrefix,
    timestamp:    Date.now(),
}, user.merchantKey));

let {code: authCode} = await connection.authenticateSms({
    code:         code,
    mobile:       user.mobile,
    mobilePrefix: user.mobilePrefix,
    smsCode:      "000000", //User receives verification code via mobile phone
});


// Install @onelabs/sui node-rsa
// npm i @onelabs/sui @onelabs/bcs node-rsa --save

const zk               = require('@onelabs/sui/zklogin');
const {Ed25519Keypair} = require('@onelabs/sui/keypairs/ed25519');
const {fromB64}        = require('@onelabs/bcs');
const _                = require('lodash');
const NodeRSA          = require('node-rsa');
const {
        SuiClient,
        getFullnodeUrl,
      }                = require('@onelabs/sui/client');

const provider = new SuiClient({ url: getFullnodeUrl('devnet') });

const rsaEncrypt = (options, privateKey) => {
    let rsa  = new NodeRSA(privateKey, "pkcs8-private");
    let keys = _.sortBy(_.keys(options));
    let str  = [];
    _.each(keys, (key) => {
        if (!_.includes([null, undefined, ""], options[key])) {
            let value = _.isArray(options[key]) ? JSON.stringify(options[key]) : options[key];
            str.push(`${key}=${value}`);
        }
    });
    options.merchantSign = rsa.sign(Buffer.from(str.join("&")), "base64", "utf8");
    return options;
};

// Get one chain current system info
const geSystemState = async () => {
    const systemState = await provider.getLatestSuiSystemState();
    return _.pick(systemState, ["epoch", "epochDurationMs", "epochStartTimestampMs"]);
};

// Use zklogin sign transaction
const zkSignTransaction = async (user, rawTransaction) => {
    let {signature: userSignature} = await Ed25519Keypair.fromSecretKey(user.zk.ephemeralKeyPair.secretKey).signTransaction(fromB64(rawTransaction));
    return zk.getZkLoginSignature({
        inputs:   {
            ...user.zk.zkpoof,
            addressSeed: user.addressSeed,
        },
        maxEpoch: user.zk.maxEpoch,
        userSignature,
    });
};

const generateZk = async () => {
    const suiSysState                = await geSystemState();
    const ephemeralKeyPair           = new Ed25519Keypair();
    const maxEpoch                   = Number(suiSysState.epoch) + 2;
    const randomness                 = zk.generateRandomness();
    const nonce                      = zk.generateNonce(ephemeralKeyPair.getPublicKey(), maxEpoch, randomness);
    const extendedEphemeralPublicKey = zk.getExtendedEphemeralPublicKey(ephemeralKeyPair.getPublicKey());
    return {
        maxEpoch,
        randomness,
        ephemeralKeyPair: {
            secretKey: ephemeralKeyPair.getSecretKey(),
            keyScheme: ephemeralKeyPair.getKeyScheme(),
        },
        nonce,
        extendedEphemeralPublicKey,
        suiSysState
    };
};


let zkConfig = await generateZk();
user.zk = zkConfig;

//Get login token and gwt token
let tokenResponse = await connection.zkLogin({
    code:  authCode,
    nonce: user.zk.nonce,
});

// TODO Set login token to connection headers.
connection.setToken({
    ACCESS_TOKEN: tokenResponse.accessToken,
});

user.accessToken = tokenResponse.accessToken;
user.decodedJwt  = tokenResponse.accessTokenProfile;
user.jwtToken    = tokenResponse.jwtToken;
user.salt        = tokenResponse.salt;
user.addressSeed = zk.genAddressSeed(tokenResponse.salt, "sub", tokenResponse.accessTokenProfile.sub, tokenResponse.accessTokenProfile.aud).toString();
user.address     = zk.jwtToAddress(tokenResponse.jwtToken, tokenResponse.salt);
user.did         = tokenResponse.did;

// Get zkpoofs

user.zk.zkpoof = await connection.getZkProofs({
    maxEpoch:                   user.zk.maxEpoch,
    jwtRandomness:              user.zk.randomness,
    extendedEphemeralPublicKey: user.zk.extendedEphemeralPublicKey,
    jwt:                        user.jwtToken,
    salt:                       user.salt,
    keyClaimName:               "sub",
});

//Cache user to storage

Build transaction and sign it to send

// Build and send transfer transaction
let transferTx = await connection.buildTransferTransaction({
    amount:      1,
    currency:    "USDH",
    remark:      "wallet js sdk test",
    fromAddress: user.address,
    toAddress:   Ed25519Keypair.generate().getPublicKey().toSuiAddress()
});

// Signing with ZkLogin
const zkLoginSignature = await zkSignTransaction(user, transferTx.rawTransaction);

//Broadcast and execute transactions
const transaction = await connection.sendTransferTransaction({
    hash: transferTx.hash,
    txBytes: transferTx.rawTransaction,
    userSig: zkLoginSignature,
})
console.log(transaction);