WEB3DEV

Cover image for Implementar contas multisig na Polkadot
Adriano P. Araujo
Adriano P. Araujo

Posted on

Implementar contas multisig na Polkadot

Neste tutorial, abordaremos o processo de criação de uma multisig - uma conta que compartilha autorização para transações em vários endereços.

Introdução

Neste tutorial, abordaremos o processo de criação de uma multisig - uma conta que compartilha autorização  para transações em vários endereços. A palavra "multisig" significa "assinatura múltipla". Para os fins deste tutorial, geraremos duas contas adicionais e garantiremos que ambas sejam financiadas com WND suficiente para cobrir o depósito existencial e enviar algumas transações. Estes serão usados para simular as outras partes assinantes da carteira multisig.

Criaremos um novo aplicativo de linha de comando em JavaScript para lidar com as operações de criação e uso dessa conta multisig no Westend, embora os mesmos conceitos e a maior parte do código ainda se apliquem à Polkadot ou a outras blockchains baseadas no Substrate.

Existem muitas aplicações em potencial desse conceito; no entanto, para este tutorial, estamos preocupados principalmente com a camada adicional de segurança da conta. Essa funcionalidade está no centro de muitas DAOs e estruturas de governança semelhantes. Uma conta multisig é em si uma forma de governança on-chain e uma multisig geralmente requer participação ativa.

Confira o Documentação da API da Polkadot para um resumo de todos os metadados relevantes da API.

Na documentação da API Polkadot JS:

É possível criar uma conta com várias assinaturas em cadeias baseadas no Substrate. Uma conta com várias assinaturas é composta por um ou mais endereços e um limite. O limite define quantos signatários ( endereços participantes ) precisam concordar com o envio de um extrínseco para que a chamada seja bem-sucedida. Por exemplo, Alice, Bob e Charlie montaram uma multi-sig com um limite de 2. Isso significa que Alice e Bob podem executar qualquer chamada, mesmo que Charlie discorde. Da mesma forma, Charlie e Bob podem executar qualquer ligação sem Alice. Um limite é tipicamente um número menor que o número total de membros, mas também pode ser igual a ele, o que significa que todos precisam estar de acordo.

também:

Contas com várias assinaturas não podem ser modificadas após serem criadas. Alterar o conjunto de membros ou alterar o limite não é possível e, em vez disso, requer a dissolução da atual multi-sig e a criação de uma outra. Como tal, os endereços de conta multi-sig são determinísticos, ou seja, você sempre pode calcular o endereço de uma multi-sig apenas conhecendo os membros e o limite, sem que a conta ainda exista. Isso significa que é possível enviar tokens para um endereço que ainda não existe e se as entidades designadas como destinatários se reunirem em uma nova multi-sig sob um limite correspondente, eles terão acesso imediato a esses tokens.

também:

Embora Westend pretenda replicar a rede principal da Polkadot o mais próximo possível, existem algumas diferenças notáveis:

  • Depósito existencial é igual a 0,01 WND ( Westies; Moeda nativa de Westend ) em vez de 1 DOT.

  • O depósito de transação com várias assinaturas é igual a ~ 1 WND em vez de ~ 20.2 DOT.

Configuração

Não é um requisito, no entanto, concluir o Polkadot Pathway e o tutorial de recuperação social  formam uma forte base de entendimento que aprimorará este tutorial.

A maneira mais simples de satisfazer esses requisitos e manter a flexibilidade como usuário do Windows 10 é instalar WSL2 e VSCode - a janela do terminal dentro do VSCode pode utilizar qualquer shell, da bash ao PowerShell. Os usuários de Linux e macOS não precisam do WSL2 e podem usar qualquer aplicativo de terminal e editor de texto de sua escolha.

  • Node.js instalado, de preferência com uma ferramenta para gerenciamento de versão - nvm ou fnm são escolhas populares

  • Um gerenciador de pacotes como npm ou yarn - a instalação variará de acordo com o sistema operacional

Este tutorial possui as duas dependências a seguir que devem ser instaladas através do gerenciador de pacotes :

Inicialize o diretório do projeto


mkdir polkadot_ms
cd polkadot_ms
npm init -y
npm install --save dotenv @polkadot/api

Enter fullscreen mode Exit fullscreen mode

Quando copiamos e colamos todos os quatro comandos em um terminal, os três primeiros serão executados em sequência porque possuem um caractere de  código de fim de linha (enter). mkdir polkadot_ms criará um novo subdiretório chamado polkadot_ms, então o comando cd altera o diretório de trabalho. npm init -yvai emitir o conteúdo do padrão package.json para o terminal. Neste ponto, a parte npm install estará na linha de comando, no entanto ainda devemos pressionar Enter para iniciar o processo de instalação.

Quando o processo de instalação estiver concluído, crie um arquivo .env no diretório do projeto. Por conveniência, copie e cole o modelo abaixo. Leia mais sobre dotenv  em nosso  guia de referência rápida. Lembre-se também de substituir API_KEY por uma chave API válida do DataHub do Painel de serviços Polkadot.

Cole o seguinte no seu arquivo.env:


MULTISIG_ADDRESS=

ALICE_ADDRESS=
ALICE_MNEMONIC= 


BOB_ADDRESS=
BOB_MNEMONIC=



CHARLIE_ADDRESS= 
CHARLIE_MNEMONIC=

Enter fullscreen mode Exit fullscreen mode

Crie 3 contas

Crie um arquivo chamado create_account.js e cole o seguinte código :

// create_account.js

const { ApiPromise, Keyring } = require('@polkadot/api');
const { HttpProvider } = require('@polkadot/rpc-provider');
const { mnemonicGenerate } = require('@polkadot/util-crypto');
require("dotenv").config();

const main = async () => {
  const httpProvider = new HttpProvider(process.env.DATAHUB_URL);
  const api = await ApiPromise.create({ provider: httpProvider });
  const keyring = new Keyring({type: 'sr25519'});
  const mnemonic = mnemonicGenerate();
  const newAccount = await keyring.addFromUri(mnemonic);
  console.log(`address: ${newAccount.address}`);
  console.log(`mnemonic: ${mnemonic}`);

};

main().catch((err) => {console.error(err)}).finally(() => process.exit());

Enter fullscreen mode Exit fullscreen mode

Em uma janela do terminal, execute node create_account.js 3 (três) vezes para gerar os dados que necessitamos. Copie / cole os mnemônicos e endereços para cada nova conta no modelo .env.

  • Alice: A conta que usaremos na carteira multisig.

  • Bob & Charlie: Essas contas representam outros participantes do multisig.

Financie a conta Alice visitando https://faucet.figment.io e digitando o endereço que geramos para Alice. Isso fornecerá tokens WND suficientes para essa conta para concluirmos o tutorial com muitos itens restantes para teste. Como precisaremos pagar as taxas pelas transações durante o tutorial, também será necessário transferir alguns tokens para as outras contas.

Existem três tipos de ações a serem tomadas com uma conta multi-sig. Executar uma chamada, aprovar uma chamada ou cancelar uma chamada.

Crie uma conta Multisig

Clique para ampliar

Crie um arquivo chamado create_multisig.js e cole o seguinte código :

const { ApiPromise, Keyring } = require('@polkadot/api');
const { sortAddresses, encodeMultiAddress } = require('@polkadot/util-crypto');
const { HttpProvider } = require('@polkadot/rpc-provider');
require("dotenv").config();


const main = async () => {
  const httpProvider = new HttpProvider(process.env.DATAHUB_URL);
  const api = await ApiPromise.create({ provider: httpProvider });
  const keyring = new Keyring({type: 'sr25519'});
  // 1. Define as constantes relevantes

  const INDEX = 0;
  const THRESHOLD = 2;
  const SS58PREFIX = 0;
  const AMOUNT_TO_SEND = 1000000000000;

  // 2. Inicializa as contas

  const Alice = keyring.addFromUri(process.env.ALICE_MNEMONIC);
  const Bob = keyring.addFromUri(process.env.BOB_MNEMONIC);
  const Charlie = keyring.addFromUri(process.env.CHARLIE_MNEMONIC);
  const addresses = [
    Alice.address,   // addresses[0]
    Bob.address,     // addresses[1]
    Charlie.address, // addresses[2]

  ];

  // 3.Cria Multisig (com operacional SS58PREFIX)
  const multisig = encodeMultiAddress(addresses, THRESHOLD);
  console.log(`Multisig Address: ${multisig}\n`);


  // 4. Filtra o remetente

  const otherSignatories = addresses.filter((who) => who !== addresses[INDEX]);
  const otherSignatoriesSorted = sortAddresses(otherSignatories);
  console.log(`Other Signatories: ${JSON.stringify(otherSignatoriesSorted, null, 2)}\n`);  


  // 4. Define um array de transações

  const transactions = [
     api.tx.balances.transfer(Bob.address, AMOUNT_TO_SEND),
     api.tx.balances.transfer(Charlie.address, AMOUNT_TO_SEND),

  ];


  // 5. Envia oLote 1 WND para outros endereços
  // Isso é necessário para poder assinar e enviar transações com estas contas
  const txHash = await api.tx.utility
    .batch(transactions)
    .signAndSend(Alice);
  console.log(`Sending 1 WND from ${Alice.address} to ${otherSignatories}`); 
  console.log(`transfer tx: https://westend.subscan.io/extrinsic/${txHash}`);
};

main().catch((err) => { console.error(err) }).finally(() => process.exit());

Enter fullscreen mode Exit fullscreen mode
  • SS58PREFIX é usado para codificar nosso endereço para uso em diferentes cadeias. O valor 0 codificará nosso endereço multisig para a cadeia de relés Polkadot; portanto, o endereço codificado começará com o número 1 . A equipe Parity mantém um registro dos tipos SS58, o que pode ser útil ao trabalhar com várias parachains.

  • INDEX será usado para se referir ao índice de nosso endereço em uma matriz de endereços. Mais informações sobre matrizes indexadas a zero, para os curiosos.

  • THRESHOLD especifica o número de contas necessárias para aprovar uma transação da Multisig. É possível definir o limite para o mesmo número de endereços totais, o que significaria que nenhuma transação poderia ser enviada dessa multisig sem a aprovação total, no entanto, neste exemplo, definiremos como necessárias 2 de 3 assinaturas.

  • otherSignatories ilustra o uso de filter() para remover o endereço no índice especificado. Antes de exibirmos a lista filtrada de endereços, a função sortAddresses() irá classificá-lo por chave pública. Registrando isso via JSON.stringify() será exibidoem um formato mais legível no terminal.

  • encodeMultiAddress() faz parte da matriz de endereços, THRESHOLD & e opcionalmente oSS58PREFIX e retorna o endereço determinístico da multisig. Se o prefixo SS58 estiver incluído, o endereço será codificado para a cadeia especificada.

Execute o código com node create_multisig.js :

Multisig Address: 5CPnQhU8TCvtbaJQEYEPuYhgbwpeGqhx6uErZJ7QDcaD7aX9
Other Signatories: [
  "5GL63QD2HhXvBMcP9skdjq8H5Znhe7Fke83aWENHPGRMvJSA",
  "5GpDZiUMpdX2GcGJzAZVX36kSGoScraCLEjTTgvhufEokRCX"
]
Sending 1 WND from 5Ekc5BsbkAgSbSYwi4W1CnpYLFzwUDJ4WGvohSzNcau2ZDLp 
to 5GL63QD2HhXvBMcP9skdjq8H5Znhe7Fke83aWENHPGRMvJSA, 5GpDZiUMpdX2GcGJzAZVX36kSGoScraCLEjTTgvhufEokRCX

transfer tx: [https://westend.subscan.io/extrinsic/…](https://westend.subscan.io/extrinsic/%E2%80%A6)

Enter fullscreen mode Exit fullscreen mode

Lembre-se de copiar e colar o valor resultante para o endereço Multisig em .env  como MULTISIG_ADDRESS em preparação para o próximo passo!

Financiar uma conta Multisig

Clique para ampliar

O financiamento da carteira multisig é uma etapa importante nesse processo do tutorial, para que ela tenha saldo disponível suficiente para cobrir o depósito existencial e um saldo disponível para o envio de transações adicionais.

Crie um arquivo chamado fund_multisig.js e cole o seguinte código :

const { ApiPromise, Keyring } = require('@polkadot/api');
const { HttpProvider } = require('@polkadot/rpc-provider');
const { formatBalance } = require('@polkadot/util/format');
require("dotenv").config();
const main = async () => {
  const httpProvider = new HttpProvider(process.env.DATAHUB_URL);
  const api = await ApiPromise.create({ provider: httpProvider });
  const keyring = new Keyring({type: 'sr25519'});
  // 1. Define as constantes relevantes

   formatBalance.setDefaults({
    unit: 'WND',
    decimals: 12,

  });


  // 2.  Define as constantes relevantes

  const MULTISIG = process.env.MULTISIG_ADDRESS;
  const AMOUNT_TO_SEND = 2000000000000;
  const displayAmount = formatBalance(AMOUNT_TO_SEND); // 2.0000 WND

  // 3. Inicializa a conta
  const Alice = keyring.addFromUri(process.env.ALICE_MNEMONIC)

  // 4.Envia  2 WND para conta multisig 
  const txHash = await api.tx.balances
    .transfer(MULTISIG, AMOUNT_TO_SEND)
    .signAndSend(Alice);
  console.log(`Sending ${displayAmount} from ${Alice.address} to ${MULTISIG}`); 
  console.log(`transfer tx: https://westend.subscan.io/extrinsic/${txHash}`);
};
main().catch((err) => { console.error(err) }).finally(() => process.exit());


Enter fullscreen mode Exit fullscreen mode

A função formatBalance.setDefaults() nos permite especificar um nome de unidade e casas decimais. Como estamos operando na rede de testes Westend, o WND é apropriado. Como podemos ver, AMOUNT_TO_SEND será especificado como um grande número - 2 trilhões de pWND **** (p para pico, denotando um fator de, neste caso ) - embora possamos exibi-lo de maneira legível e pré-formatada usando formatBalance() . Pode ser útil visualizar amountToSend em doze casas decimais como esta :

// 2,000,000,000,000 = 2.0 WND

Para concluir a ação de financiar a conta multisig especificada, pagando com o saldo disponível de Alice, nós usamos api.tx.balances para acessar o método transfer() e depois signAndSend() . Isso realizará a criação da conta multisig ( fornecendo o depósito existencial ) enquanto transfere 2 WND para ela.

Execute o código com node fund_multisig.js :

Sending 2.0000 WND 
from 5Ekc5BsbkAgSbSYwi4W1CnpYLFzwUDJ4WGvohSzNcau2ZDLp 
to 5CPnQhU8TCvtbaJQEYEPuYhgbwpeGqhx6uErZJ7QDcaD7aX9
transfer tx: [https://westend.subscan.io/extrinsic/…](https://westend.subscan.io/extrinsic/%E2%80%A6)

Enter fullscreen mode Exit fullscreen mode

A páginaSubScan incluirá esses 4 eventos. Consulte os seguintes exemplos de eventos bem-sucedidos.

Executar uma transferência Multisig

Clique para ampliar.

Crie um arquivo chamado transfer_multisig.js e cole o seguinte código :

const { ApiPromise, Keyring } = require('@polkadot/api');
const { HttpProvider } = require('@polkadot/rpc-provider');
const { formatBalance } = require('@polkadot/util/format')
require("dotenv").config();

const main = async () => {
  const httpProvider = new HttpProvider(process.env.DATAHUB_URL);
  const api = await ApiPromise.create({ provider: httpProvider });
  const keyring = new Keyring({type: 'sr25519'});
  // 1. Use formatBalance para exibir os valores
  formatBalance.setDefaults({
    unit: 'WND',
    decimals: 12,
  });

  // 2. Define constantes relevantes

  const THRESHOLD = 2;
  const MAX_WEIGHT = 640000000;
  const AMOUNT_TO_SEND = 1000000000000;
  const MULTISIG = process.env.MULTISIG_ADDRESS;
  const displayAmount = formatBalance(AMOUNT_TO_SEND);
  const depositBase = api.consts.multisig.depositBase;
  const depositFactor = api.consts.multisig.depositFactor;


  // 3. Inicializa as contas 

 const Alice = keyring.addFromUri(process.env.ALICE_MNEMONIC);
  const Bob = keyring.addFromUri(process.env.BOB_MNEMONIC);
  const Charlie = keyring.addFromUri(process.env.CHARLIE_MNEMONIC);
  const otherSignatories = [
    Bob.address,
    Charlie.address,
  ].sort();



  // 4. Chamadas API - dados são necessários para o timepoint

  const call = api.tx.balances.transfer(Charlie.address, AMOUNT_TO_SEND);
  const info = await api.query.multisig.multisigs(MULTISIG, call.method.hash); 
  // 5. Define o timepoint
  // se esta É a primeira aprovação estão deve retornar  None (null)
  const TIME_POINT = null;
  // Se esta  NÃO é a primeira aprovação então deve retornar Some
// Com o timepoint  (número do bloco e índice da transação), da primeira transação de aprovação
  // const TIME_POINT = info.unwrap().when;
  // 6. approveAsMulti 
  const txHash = await api.tx.multisig
    .approveAsMulti(THRESHOLD, otherSignatories, TIME_POINT, call.method.hash, MAX_WEIGHT)
    .signAndSend(Alice);
  console.log(`depositBase   : ${depositBase}`);
  console.log(`depositFactor : ${depositFactor}`);
  console.log(`Sending ${displayAmount} from ${Alice.address} to ${MULTISIG}`); 
  console.log(`Required values  : approveAsMulti(THRESHOLD, otherSignatories, TIME_POINT, call.method.hash, MAX_WEIGHT)`);
  console.log(`Submitted values : approveAsMulti(${THRESHOLD}, otherSignatories: ${JSON.stringify(otherSignatories, null, 2)}, ${TIME_POINT}, ${call.method.hash}, ${MAX_WEIGHT})\n`); 
  console.log(`approveAsMulti tx: https://westend.subscan.io/extrinsic/${txHash}`);  
};
main().catch((err) => { console.error(err) }).finally(() => process.exit());

Enter fullscreen mode Exit fullscreen mode
  • THRESHOLD e otherSignatories deve ser conhecido, TIME_POINT deve ser null se esta é a primeira aprovação para o multisig. call.method.hash faz o que diz, retornando uma representação de hash dos dados do método da transferência.

  • MAX_WEIGHT refere-se ao peso máximo da chamada, embora isso não esteja claramente indicado na documentação da API, ele tem a ver com o cálculo da taxa. O peso é um número fixo projetado para gerenciar os tempos de validação de blocos. Pode ser complementado com uma dica opcional. Leia mais sobre as taxas de transação Polkadot aqui.

Execute o código com node transfer_multisig.js :

depositBase   : 1.0044 WND
depositFactor : 1.6000 mWND
Sending 1.0000 WND
 from 5Ekc5BsbkAgSbSYwi4W1CnpYLFzwUDJ4WGvohSzNcau2ZDLp
 to 5CPnQhU8TCvtbaJQEYEPuYhgbwpeGqhx6uErZJ7QDcaD7aX9
Required values  : approveAsMulti(THRESHOLD, otherSignatories, TIME_POINT, call.method.hash, MAX_WEIGHT)
Submitted values : approveAsMulti(2, otherSignatories: [
  "5GL63QD2HhXvBMcP9skdjq8H5Znhe7Fke83aWENHPGRMvJSA",
  "5GpDZiUMpdX2GcGJzAZVX36kSGoScraCLEjTTgvhufEokRCX"
], null, 0xb9533f7199a78343facd0fa13e15a08b3620c75dfe49c37660e832a0cb1ff146, 640000000)

approveAsMulti tx: [https://westend.subscan.io/extrinsic/…](https://westend.subscan.io/extrinsic/%E2%80%A6)

Enter fullscreen mode Exit fullscreen mode

Aprovar uma transferência Multisig

Clique para ampliar.

Crie um novo arquivo chamado approve_multisig.js e cole o seguinte código :

const { ApiPromise, Keyring } = require('@polkadot/api');
const { HttpProvider } = require('@polkadot/rpc-provider');
const { formatBalance } = require('@polkadot/util/format')
require("dotenv").config();

const main = async () => {
  const httpProvider = new HttpProvider(process.env.DATAHUB_URL);
  const api = await ApiPromise.create({ provider: httpProvider });
  const keyring = new Keyring({type: 'sr25519'});
  // 1. Usa o formatBalance para exibir os valores
   formatBalance.setDefaults({
    unit: 'WND',
    decimals: 12,
  });

  // 2. Define as constantes relevantes
  const THRESHOLD = 2;
  const STORE_CALL = false;
  const MAX_WEIGHT = 640000000;
  const AMOUNT_TO_SEND = 1000000000000;
  const MULTISIG = process.env.MULTISIG_ADDRESS;
  const displayAmount = formatBalance(AMOUNT_TO_SEND);
  // 3. Inicializa as contas
  const Alice = keyring.addFromUri(process.env.ALICE_MNEMONIC);
  const Bob = keyring.addFromUri(process.env.BOB_MNEMONIC);
  const Charlie = keyring.addFromUri(process.env.CHARLIE_MNEMONIC);
  const otherSignatories = [
    Alice.address,
    Charlie.address,
  ].sort();

  // 4. Envia 1 WND para a conta  Charlie 
  const call = api.tx.balances.transfer(Charlie.address, AMOUNT_TO_SEND);

  // 5. Recupera e desempacota o ponto de parada

  const info = await api.query.multisig.multisigs(MULTISIG, call.method.hash);
  const TIME_POINT= info.unwrap().when;
  console.log(`Time point is: ${TIME_POINT}`);

  // 6. Envia a transação asMulti 
  //Agora a chamada multisig que foi iniciada pela conta da Alice envia 1  WND para Charlie que  é aprovado pelo Bob.
  // Como o limite é definido como 2 , essa aprovação deve enviar a chamada  
// (Recebimento de 2 chamadas) 

  const txHash = await api.tx.multisig
    .asMulti(THRESHOLD, otherSignatories, TIME_POINT, call.method.toHex(), STORE_CALL, MAX_WEIGHT)
    .signAndSend(Bob);
  console.log(`Sending ${displayAmount} from ${MULTISIG} to ${Charlie.address}`); 
  console.log(`Required values  : asMulti(THRESHOLD, otherSignatories, TIME_POINT, call.method.hash, MAX_WEIGHT)`);
  console.log(`Submitted values : asMulti(${THRESHOLD}, otherSignatories: ${JSON.stringify(otherSignatories, null, 2)}, ${TIME_POINT}, ${call.method.hash}, ${MAX_WEIGHT})\n`); 
  console.log(`asMulti tx: https://westend.subscan.io/extrinsic/${txHash}`);
}main().catch((err) => { console.error(err) }).finally(() => process.exit());

Enter fullscreen mode Exit fullscreen mode

call.method.toHex() difere de call.method.hash em que toHex() só vai passar uma representação hexadecimal do método, mas não o método completo.

Se encontrarmos Error: Option: unwrapping a None value significa que a chamada unwrap() n consulta da API encontrou um valor Nenhum quando esperava Algum valor ( um ponto de tempo válido ). Provavelmente isso seria devido ao api.query.multisig.multisigs() não tendo um ponto de tempo associado - indicando a ausência de approveAsMulti() . Em essência, não há dados sobre os quais agir neste caso - possivelmente por tentar executar approve_multisig.js antes de transfer_multisig.js.

Execute o código com node approve_multisig.js :

The timepoint is: {"height":5556711,"index":2}
Sending 1.0000 WND 
from 5CPnQhU8TCvtbaJQEYEPuYhgbwpeGqhx6uErZJ7QDcaD7aX9 
to 5GpDZiUMpdX2GcGJzAZVX36kSGoScraCLEjTTgvhufEokRCX
asMulti tx: [https://westend.subscan.io/extrinsic/…](https://westend.subscan.io/extrinsic/%E2%80%A6)

Enter fullscreen mode Exit fullscreen mode

Cancelar uma transferência multisig

Crie um novo arquivo chamado cancel_multisig.js e cole o seguinte código :

const { ApiPromise, Keyring } = require('@polkadot/api');
const { HttpProvider } = require('@polkadot/rpc-provider');
const { formatBalance } = require('@polkadot/util/format')
require("dotenv").config();

const main = async () => {
  const httpProvider = new HttpProvider(process.env.DATAHUB_URL);
  const api = await ApiPromise.create({ provider: httpProvider });
  const keyring = new Keyring({type: 'sr25519'});
  // 1. Usa formatBalance para exibir os valores
   formatBalance.setDefaults({
    unit: 'WND',
    decimals: 12,
  });


  // 2. Define as constantes relevantes
  const THRESHOLD = 2;
  const STORE_CALL = false;
  const MAX_WEIGHT = 640000000;
  const AMOUNT_TO_SEND = 1000000000000;
  const MULTISIG = process.env.MULTISIG_ADDRESS;
  const displayAmount = formatBalance(AMOUNT_TO_SEND);
  // 3. Inicializa as contas
  const Alice = keyring.addFromUri(process.env.ALICE_MNEMONIC);
  const Bob = keyring.addFromUri(process.env.BOB_MNEMONIC);
  const Charlie = keyring.addFromUri(process.env.CHARLIE_MNEMONIC);
  const otherSignatories = [
    Alice.address,
    Charlie.address,
  ].sort();

  // 4. Envia 1 WND para conta Charlie
  // Essa é a transação   multisig que nós queremos cancelar
  const call = api.tx.balances.transfer(Charlie.address, AMOUNT_TO_SEND);

  // 5. Recupera e desempacota timepoint
  const info = await api.query.multisig.multisigs(MULTISIG, call.method.hash);
  const TIME_POINT= info.unwrap().when;
  console.log(`Time point is: ${TIME_POINT}`);
  // 6. Cancela a transação asMulti 
  const txHash = await api.tx.multisig
   .cancelAsMulti(THRESHOLD, otherSignatories, TIME_POINT, call.method.hash)
   .signAndSend(Bob);

  console.log(`Sending ${displayAmount} from ${MULTISIG} to ${Charlie.address}`); 
  console.log(`Required values  : cancelAsMulti(THRESHOLD, otherSignatories, TIME_POINT, call.method.hash)`);
  console.log(`Submitted values : cancelAsMulti(${THRESHOLD}, otherSignatories: ${JSON.stringify(otherSignatories, null, 2)}, ${TIME_POINT}, ${call.method.hash})\n`); 
  console.log(`cancelAsMulti tx: https://westend.subscan.io/extrinsic/${txHash}`);
}

main().catch((err) => { console.error(err) }).finally(() => process.exit());

Enter fullscreen mode Exit fullscreen mode

Não é necessário executar este código no curso normal do tutorial, ele é em grande parte incluído aqui por uma questão de integridade. Isso seria útil caso uma transação de aprovação multisig fique paralisada ou precise ser cancelada por qualquer motivo. Caso seja necessário ou para fins de teste, execute o código com node cancel_multisig.js :

Time point is: {"height":5557129,"index":2}
Sending 1.0000 WND 
from 5CPnQhU8TCvtbaJQEYEPuYhgbwpeGqhx6uErZJ7QDcaD7aX9
to 5GpDZiUMpdX2GcGJzAZVX36kSGoScraCLEjTTgvhufEokRCX
Required values  : cancelAsMulti(THRESHOLD, otherSignatories, TIME_POINT, call.method.hash)
Submitted values : cancelAsMulti(2, otherSignatories: [
  "5GL63QD2HhXvBMcP9skdjq8H5Znhe7Fke83aWENHPGRMvJSA",
  "5GpDZiUMpdX2GcGJzAZVX36kSGoScraCLEjTTgvhufEokRCX"
], {"height":5557129,"index":2}, 0xb9533f7199a78343facd0fa13e15a08b3620c75dfe49c37660e832a0cb1ff146) 

cancelAsMulti tx: [https://westend.subscan.io/extrinsic/0x774822d10f1159f12491bf9351a7b043100ccac88f5ed2c34ab1eac07fe190fe](https://westend.subscan.io/extrinsic/0x774822d10f1159f12491bf9351a7b043100ccac88f5ed2c34ab1eac07fe190fe)

Enter fullscreen mode Exit fullscreen mode

Conclusão

Parabéns! Este tutorial abordou a criação e o uso de uma conta multisig usando a API Polkadot JS. Agora podemos iniciar, aprovar e cancelar transações usando uma conta que requer várias autorizações. Essa funcionalidade permite que muitas outras coisas incríveis sejam construídas no Polkadot, e todos esperamos ver o que você constrói usando contas multisig.


Este artigo foi escrito por Rogan X  e traduzido por Adriano P. de Araujo. O original em inglês pode ser encontrado aqui.

Top comments (0)