多簽是甚麼:
一個Account 由多個使用者進行管理,而每個使用者都至少握有一把private key。
建立多簽帳戶:
1.新增多簽帳戶時就要確定參與多簽的人數。
2.以及要幾把私鑰才可以交易成功。
3.產生Private key and Public Key -> 產生 Auth Key -> Address
情況範例:
1.每把鑰匙的權重一樣
假設有A,B,C,D,E五把鑰匙,他們共管理一個帳戶,只需要三把就可以通過交易。
2.A的權重比別較多,其餘每把鑰匙的權重一樣
假設這個多簽帳戶是由A,A,B,C,D,這五把鑰匙組成的,只需要三把就可以通過交易。
(但因為A這把鑰匙的權重大,只需要他簽一次,隨便其他人在簽一次就可)
應用在哪:
1.多裝置驗證
2.鑰匙備份
3.管理帳務
4.管理NFT的發放
沒有多簽帳戶:
1.新建多簽帳戶,確定多少人要參與加簽
2.要幾把鑰匙才算通過 (確定需要多少人簽核這筆交易)
3.1 建立多簽帳戶
3.2 進行faucet
4.紀錄多簽賬戶的Address、PublicKey
(以後在發起交易、簽核交易會用到)
發起交易:
1.輸入要參與交易的帳戶的地址和privateKey
2.輸入目標地址
3.輸入金額
4.加簽交易
5.發起交易
建立多簽帳戶:
步驟1:引入套件、物件
import { AptosClient, AptosAccount, FaucetClient, BCS, TransactionBuilderMultiEd25519, TxnBuilderTypes } from "aptos";
步驟2:設定連接節點、鏈的資訊
const NODE_URL = process.env.APTOS_NODE_URL || "https://fullnode.devnet.aptoslabs.com";
const FAUCET_URL = process.env.APTOS_FAUCET_URL || "https://faucet.devnet.aptoslabs.com";
步驟3:初始化本地端(客戶端)連結鏈的物件,利用這物件跟鏈取得資料
const client = new AptosClient(NODE_URL);
步驟4:初始化水龍頭物件
const faucetClient = new FaucetClient(NODE_URL, FAUCET_URL);
步驟5:創建要參與加簽的帳戶
const account1 = new AptosAccount();
const account2 = new AptosAccount();
const account3 = new AptosAccount();
筆記:
如果是現有帳戶,可以輸入privatekey、address
步驟6:建立多簽帳戶、設定多少private才能通過交易,這邊會產出public key
const multiSigPublicKey = new TxnBuilderTypes.MultiEd25519PublicKey(
[
new TxnBuilderTypes.Ed25519PublicKey(account1.signingKey.publicKey),
new TxnBuilderTypes.Ed25519PublicKey(account2.signingKey.publicKey),
new TxnBuilderTypes.Ed25519PublicKey(account3.signingKey.publicKey),
],
// Threshold
2,
);
步驟7:公鑰產出Authentication key
const authKey = TxnBuilderTypes.AuthenticationKey.fromMultiEd25519PublicKey(multiSigPublicKey);
步驟8:導出帳戶Address
const mutisigAccountAddress = authKey.derivedAddress();
步驟9:水管匯入APT Token
await faucetClient.fundAccount(mutisigAccountAddress, 100_000_000);
筆記:
如果Account 要記錄在鏈上,就必須水管匯入APT 0個也可以
步驟10:查看帳戶資源
let resources = await client.getAccountResources(mutisigAccountAddress);
let accountResource = resources.find((r) => r.type === aptosCoinStore);
let balance = parseInt((accountResource?.data as any).coin.value);
assert(balance === 100_000_000);
console.log(`multisig account coins: ${balance}. Should be 100000000!`);
發起多簽交易:
步驟1:建立傳送的帳號地址
const account4 = new AptosAccount();
// Creates a receiver account and fund the account with 0 AptosCoin
await faucetClient.fundAccount(account4.address(), 0);
resources = await client.getAccountResources(account4.address());
accountResource = resources.find((r) => r.type === aptosCoinStore);
balance = parseInt((accountResource?.data as any).coin.value);
assert(balance === 0);
console.log(`account4 coins: ${balance}. Should be 0!`);
步驟2:取得要交易的Token,交易的Module
const token = new TxnBuilderTypes.TypeTagStruct(TxnBuilderTypes.StructTag.fromString("0x1::aptos_coin::AptosCoin"));
const entryFunctionPayload = new TxnBuilderTypes.TransactionPayloadEntryFunction(
TxnBuilderTypes.EntryFunction.natural(
// Fully qualified module name, `AccountAddress::ModuleName`
"0x1::coin",
// Module function
"transfer",
// The coin type to transfer
[token],
// Arguments for function `transfer`: receiver account address and amount to transfer
[BCS.bcsToBytes(TxnBuilderTypes.AccountAddress.fromHex(account4.address())), BCS.bcsSerializeUint64(123)],
),
);
步驟3:取得帳戶交易到哪一個編號和在哪一個鏈進行交易
const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
client.getAccount(mutisigAccountAddress),
client.getChainId(),
]);
步驟4:組成交易資料
const rawTxn = new TxnBuilderTypes.RawTransaction(
// Transaction sender account address
TxnBuilderTypes.AccountAddress.fromHex(mutisigAccountAddress),
BigInt(sequenceNumber),
entryFunctionPayload,
// Max gas unit to spend
BigInt(10000),
// Gas price per unit
BigInt(100),
// Expiration timestamp. Transaction is discarded if it is not executed within 10 seconds from now.
BigInt(Math.floor(Date.now() / 1000) + 10),
new TxnBuilderTypes.ChainId(chainId),
);
步驟5:新增物件,設定要用那些Private Key進行加簽
const txnBuilder = new TransactionBuilderMultiEd25519((signingMessage: TxnBuilderTypes.SigningMessage) => {
const sigHexStr1 = account1.signBuffer(signingMessage);
const sigHexStr3 = account3.signBuffer(signingMessage);
const bitmap = TxnBuilderTypes.MultiEd25519Signature.createBitmap([0, 2]);
const muliEd25519Sig = new TxnBuilderTypes.MultiEd25519Signature(
[
new TxnBuilderTypes.Ed25519Signature(sigHexStr1.toUint8Array()),
new TxnBuilderTypes.Ed25519Signature(sigHexStr3.toUint8Array()),
],
bitmap,
);
return muliEd25519Sig;
}, multiSigPublicKey);
步驟6:加簽交易
const bcsTxn = txnBuilder.sign(rawTxn);
步驟7:提交加簽資料做驗證
const transactionRes = await client.submitSignedBCSTransaction(bcsTxn);
步驟8:發送交易
await client.waitForTransaction(transactionRes.hash);
步驟9:查看多簽帳戶Resource
resources = await client.getAccountResources(mutisigAccountAddress);
accountResource = resources.find((r) => r.type === aptosCoinStore);
balance = parseInt((accountResource?.data as any).coin.value);
console.log(`multisig account coins: ${balance}.`);
步驟10:查看目標帳戶
resources = await client.getAccountResources(account4.address());
accountResource = resources.find((r) => r.type === aptosCoinStore);
balance = parseInt((accountResource?.data as any).coin.value);
assert(balance === 123);
console.log(`account4 coins: ${balance}. Should be 123!`);