您正在查看: Surou 发布的文章

eos_faucet EOS 账号水龙头

eos_faucet

server side:

cd your_working_dir

git clone https://github.com/cryptokylin/eos_faucet.git

cd eos_faucet

open wallet.py, paste account (to create account, transfer tokens) name, wallet name, wallet password accordingly, then save

python clfaucet.py

client side:

you can create at most 1000 accounts per day.

curl http://your_server_ip/create_account?<new_account_name>

you can get 100 tokens each call and max 1000 tokens per day.

curl http://your_server_ip/get_token?<your_account_name>

note:

this code is for test purpose only, you should not use it on eos mainnet with your real account

github:https://github.com/cryptokylin/eos_faucet

虚拟币硬件钱包调研

最近项目打算接硬件钱包,简单记录下调研信息
目前需求 需要支持 PC浏览器以及收集APP。
APP端的话相对较多,先查下PC浏览器相关的
主要信息来源MetaMask扩展和ScatteDesktop客户端。
目前流行的两个“龙头”PC浏览器钱包解决方案。

MetaMask

支持2种硬件钱包

  • Ledger
  • TREZOR

ScatteDesktop

也支持2种

  • Ledger Nano S
  • Scatter/LiguidEOS DIY Hardware Wallet

EOSIO

YubiKey (WebAuthn)

相关介绍

Ledger

https://shop.ledger.com/products/ledger-nano-s?r=17c4991a03fa&tracker=MY_TRACKER
https://zhuanlan.zhihu.com/p/32322818
https://weidian.com/p5/diary/pages/diary.php?id=14414801
https://0xzx.com/20190504193957697.html
https://github.com/cosmos/ledger-cosmos

Scatter/LiguidEOS DIY Hardware Wallet

https://medium.com/@liquideos/how-to-build-an-eos-hardware-wallet-a-step-by-step-guide-a62445786c0f

Yubikey

https://www.zilian8.com/148763.html

目前Yubikey 是EOSIO官方在做的,目前还没有太多的介绍,相信很快就会有了。
目前EOS已经稳定,BM下一步就是商业化产品运行,

对于开发者来说,目前Ledger的周边库是最全的,一些相关的js库等

比特币,以太坊,EOS 公私钥生成以及签名 BlockchainWallet-Crypto

BlockchainWallet-Crypto

简介

这个库到底能干什么
  1. 生成比特币公私钥地址
  2. 生成以太坊公私钥地址
  3. 根据 UTXO 信息打包比特币交易
  4. 根据 nonce 信息打包以太坊交易
  5. 对比特币交易进行签名
  6. 对以太坊交易进行签名
  7. 支持 BIP39 助记词
  8. 支持 BIP32 子私钥
  9. 支持 BIP44 多币种管理
  10. 支持 BIP38 加密私钥导入导出
  11. 支持以太坊 keystore 导入导出
  12. 生成以太坊调用智能合约的参数
  13. 生成 EOS 公私钥

EOS 从助记词生成私钥

现在 EOS 从助记词生成私钥有两种方式

  1. 12 个助记词之间用空格隔开拼接成字符串,然后 Hash 得到私钥
  2. 采用 Bip44 标准的生成方案,EOS 的币种序号详见最下方⎡相关资料⎦中的⎡Bip44 注册币种列表⎦

经过国内大部分钱包商议统一使用第二种方案解决 EOS 从助记词生成私钥的问题

欢迎给位提设计上的 lssues 和 pr

引入项目

allprojects {
  repositories {
    ...
        maven { url 'https://jitpack.io' }
  }
}

dependencies {
  implementation 'com.github.QuincySx:BlockchainWallet-Crypto:last-version'
}

使用说明

简单使用说明

相关资料

Bip44 注册币种列表

LICENSE

开源协议

github:https://github.com/QuincySx/BlockchainWallet-Crypto

ScatterDesktop Backup

BackService 调用 saveFile

export default class BackupService {

    static async setBackupStrategy(strategy){
        const scatter = store.state.scatter.clone();
        scatter.settings.autoBackup = strategy;
        return store.dispatch(Actions.SET_SCATTER, scatter);
    }

    static async createBackup(){
        const location = getFolderLocation();
        if(! location) return false;

        await saveFile(location[0]);
    }

    static async setBackupLocation(){
        const location = getFolderLocation();
        if(!location) return false;
        const scatter = store.state.scatter.clone();
        scatter.settings.backupLocation = location[0];
        return store.dispatch(Actions.SET_SCATTER, scatter);
    }

    static async createAutoBackup(){
        if(!store.state.scatter || !store.state.scatter.settings) return;
        const strategy = store.state.scatter.settings.autoBackup;
        if(!strategy || !strategy.length || strategy === BACKUP_STRATEGIES.MANUAL) return;

        const backupLocation = store.state.scatter.settings.backupLocation;
        if(!backupLocation || !backupLocation.length) return false;


        await saveFile(backupLocation);
    }

}

写入备份文件

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/BackupService.js#L12:18

const saveFile = (filepath) => {
    return new Promise(resolve => {
        const scatter = getLatestScatter();
        const date = new Date();
        const month = date.getUTCMonth();
        const year = date.getUTCFullYear();
        const salt = StorageService.getSalt();
        const file = scatter + '|SLT|' + salt;
        const name = `${filepath}/scatter__${store.state.scatter.hash.substr(0,4)}-${store.state.scatter.hash.slice(-4)}__${store.state.scatter.meta.version}__${month}-${year}.json`;
        try {
            fs.writeFileSync(name, file, 'utf-8');
            resolve(true);
        }
        catch(e) {
            console.error('Error saving file', e);
            resolve(false);
        }
    })
};

备份文件的内容

const scatter = getLatestScatter();
const salt = StorageService.getSalt();
const file = scatter + '|SLT|' + salt;
const getLatestScatter = () => StorageService.getScatter();

StorageService

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/StorageService.js#L93

export default class StorageService {

    constructor(){}

    static async setScatter(scatter){
        return new Promise(async resolve => {
            clearSaveTimeouts();
            saveResolvers.push(resolve);
            safeSetScatter(scatter, resolve);
        })
    };

    static getScatter() {
        return scatterStorage().get('scatter');
    }

actions

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/store/actions.js#L91

[Actions.SET_SCATTER]:async ({commit, state}, scatter) => {
        return new Promise(async resolve => {
            const process = Process.savingData();

            const seed = await ipcAsync('seed');
            const savable = AES.encrypt(scatter.savable(seed), seed);
            StorageService.setLocalScatter(savable);
            process.updateProgress(50);
            StorageService.setScatter(savable).then(() => {
                BackupService.createAutoBackup()
            });

            commit(Actions.SET_SCATTER, scatter);
            resolve(scatter);
            process.updateProgress(100);
        })
    },

其中的

const seed = await ipcAsync('seed');

是从

 [Actions.SET_SEED]:({commit}, password) => {
        return new Promise(async (resolve, reject) => {
            const [mnemonic, seed] = await PasswordService.seedPassword(password, true);
            resolve(mnemonic);
        })
    },

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/services/PasswordService.js#L48

static async seedPassword(password, setToState = true){
        return new Promise(async (resolve, reject) => {
            try {
                let seed, mnemonic;
                if(password.split(' ').length >= 12) {
                    seed = await Mnemonic.mnemonicToSeed(password);
                    mnemonic = password;
                } else {
                    const [m, s] = await Mnemonic.generateMnemonic(password);
                    seed = s;
                    mnemonic = m;
                }

                if(setToState) ipcFaF('seeding', seed);
                resolve([mnemonic, seed]);
            } catch(e){
                resolve([null, null]);
            }
        })
    }

Scatter

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop/-/blob/src/models/Scatter.js#L76:1

savable(seed){
        this.keychain.keypairs.map(keypair => keypair.encrypt(seed));

        const clone = this.clone();
        clone.keychain.identities.map(id => id.encrypt(seed));

        // Keychain is always stored encrypted.
        clone.encrypt(seed);

        return clone;
    }

Keychain

https://sourcegraph.com/github.com/GetScatter/ScatterDesktop@318ebfef6e383c6d2ca9d5016199b2b12a82c1a4/-/blob/src/models/Keychain.js#L20:1

static fromJson(json){
        let p = Object.assign(this.placeholder(), json);
        if(json.hasOwnProperty('keypairs')) p.keypairs = json.keypairs.map(x => Keypair.fromJson(x));
        if(json.hasOwnProperty('accounts')) p.accounts = json.accounts.map(x => Account.fromJson(x));
        if(json.hasOwnProperty('identities')) p.identities = json.identities.map(x => Identity.fromJson(x));
        if(json.hasOwnProperty('permissions')) p.permissions = json.permissions.map(x => Permission.fromJson(x));
        if(json.hasOwnProperty('apps')) p.apps = json.apps.map(x => AuthorizedApp.fromJson(x));
        return p;
    }