A lei de Moore, que era realmente mais do que uma regra de ouro, é a observação de que o número de transistores em um circuito integrado denso dobra a cada dois anos. Eu senti o impacto da lei de Moore nos primeiros anos de minha carreira, quando a revolução do PC começou a crescer.
Durante o auge da revolução dos PCs, as coisas estavam se movendo rapidamente enquanto corporações como Microsoft, Novell e Borland reivindicavam a propriedade e ajudavam a estabelecer padrões para esta nova era da computação. O fato de que a potência da CPU dobrava a cada 18 a 24 meses tornou-se um ativo muito necessário na época para permitir que características e funcionalidades complexas se tornassem realidades.
Sinto que a Web3 está em uma posição semelhante, com novas ferramentas, estruturas, protocolos e conceitos, como a multi-chain, sendo lançados constantemente. Claramente o número de opções existentes para a Web3 há 18 a 24 meses insignificante em comparação com o que está disponível hoje.
Um exemplo é como a Coinbase Cloud está aumentando seu conjunto de ferramentas – com a introdução de seu serviço Node com APIs avançadas e uma abrangente API NFT.
Neste artigo, vou mergulhar e mostrar como é fácil começar e criar algo de valor. Mas antes, vamos nos certificar de que todos estejam na mesma página.
Breve recapitulação sobre como começar com a Coinbase
Em meu último artigo nós exploramos a API da Coinbase de um ponto de partida da Web2. Para aqueles que podem ter perdido, criei uma interface simples que nos permitiu conectar nossa carteira e enviar algum ETH usando as APIs da Coinbase.
O objetivo dessa publicação era dar aos desenvolvedores da Web2 uma introdução básica para interagir com a blockchain. Ela permitiu que os primeiros usuários transferissem fundos para si mesmos - tudo por uma pequena taxa de gas.
Isto certamente não é tudo que as APIs da Coinbase têm a oferecer. E é por isso que uma progressão natural é explorar alguma nova tecnologia da Coinbase que possa tornar nosso dapp mais funcional. Os recentemente anunciados Coinbase Cloud Node e APIs NFT realmente chamaram minha atenção.
Mais sobre o Coinbase Cloud Node e APIs NFT
O Coinbase Cloud Node e as APIs NFT vêm com alguns benefícios atraentes para impulsionar a adesão dos desenvolvedores:
- A segurança no nível empresarial é incluída por padrão.
- A solução é construída por um dos líderes da Web3.
- Os desenvolvedores podem começar gratuitamente - com opções para escalar conforme for bem-sucedido.
Um dos desafios enfrentados pelos desenvolvedores da Web3 é a capacidade de consultar/fazer transações em múltiplas redes de blockchain. O serviço Coinbase Cloud Node e as APIs avançadas fazem das consultas e transações em múltiplas redes em blockchain um refresco - e incluem dados abrangentes de suas consultas.
De uma perspectiva de NFT, as APIs NFT da Coinbase podem coletar metadados de NFTs de coleções em múltiplas blockchains de forma rápida e fácil, resolvendo o mesmo problema no sempre crescente aspecto dos NFTs na Web3.
Vamos ver como podemos juntá-los para construir um dapp que exibirá os NFTs de um usuário em uma coleção. É importante notar que, em seus estados atuais, estas APIs estão atualmente disponíveis apenas na Rede Ethereum, portanto, é isso que estaremos utilizando.
Demonstração
Para a parte de demonstração deste artigo, vamos construir sobre o projeto anterior do meu último artigo e tornar nosso dapp mais funcional usando o Coinbase Cloud Node e as APIs NFT. Incluiremos as seguintes funcionalidades:
- Entre em um endereço de contrato NFT
- A API avançada do Coinbase Cloud Node lê os metadados do contrato para mostrar o nome da coleção
- A API Avançada verifica a carteira da conta conectada quanto ao número de NFTs na coleção
- Dependendo do número de NFTs, campos de entrada surgem para inserir os números de identificação do NFT
- A API NFT usa esses números de identificação para retornar as imagens dos NFTs da conta a partir dessa coleção
1. Configurando Sua Conta
Mas antes de começar com o projeto, inscreva-se em uma conta na Coinbase Cloud aqui.
Após configurar sua conta, selecione a opção Go to Node (Vá para o Node) em seu painel de controle e depois Create new project (Crie um novo projeto).
Como você pode ver na lista de redes nesta página, há muitas para escolher! No entanto, para facilitar as coisas, escolheremos a Ethereum Mainnet.
Selecione o plano Free e dê um nome ao seu projeto, depois clique no botão Go to project (Ir para projeto).
MUITO IMPORTANTE: Após clicar no botão, um diálogo aparecerá contendo seu nome de usuário e senha. NÃO FECHE ESTE DIÁLOGO ATÉ QUE VOCÊ TENHA COPIADO SUA SENHA. A Coinbase não armazena sua senha, portanto, se você não conseguir copiar sua senha, você terá que iniciar um novo projeto.
Depois de copiar seu Nome de Usuário e Senha, clique em Next para receber seu Endpoint. Copie isto junto com seu Nome de Usuário e Senha e nós usaremos tudo isso no projeto.
2. Configurando o Projeto
Para continuar com o resto do projeto, você precisará do seguinte:
- Git
- Seu editor de código preferido
- Node Package Manager (NPM)
- Uma extensão do navegador de carteira Web3, ou a Coinbase Wallet, ou a MetaMask
- Um NFT na Mainnet Ethereum (Endereço do contrato NFT e número de identificação NFT).
Se você acompanhou o meu último tutorial, Ótimo! Você já terá um ponto de partida para este aqui. Caso contrário, não se preocupe, você pode encontrar o projeto que começaremos, aqui:
https://gitlab.com/johnjvester/coinbase-wallet-example
Ou simplesmente execute este comando a partir de seu terminal no diretório no qual você deseja trabalhar:
git clone https://gitlab.com/johnjvester/coinbase-wallet-example.git
Em seguida, mude os diretórios para a nova pasta e instale as dependências:
cd coinbase-wallet-example && npm i
Agora execute npm start apenas para ter certeza de que tudo está funcionando corretamente até este ponto. Navegue até http://localhost:3000/ e você deve ter uma página que se pareça com esta.
Com sua extensão de navegador de carteira Web3 instalada, selecione Connect Wallet para conectar e mudar para a Rede Ropsten. Uma vez que isso esteja completo, você deve ver seu endereço de carteira como a Conta Conectada.
Incrível! Agora que sabemos que tudo está funcionando, vamos adicionar nossa nova funcionalidade. Abra o projeto em seu editor de código e navegue até o ./src/App.js file.
3. Mude o Código
3.a. Credenciais e Títulos
Primeiro, vamos acrescentar um pequeno código próprio. Abaixo das declarações de importação, adicionaremos nosso URL da Coinbase, nome de usuário, senha e algum código para criar os títulos que estaremos passando junto com nossas chamadas API.
A seguir, precisamos ajustar o DEFAULT_CHAIN_ID
, DEFAULT_ETHEREUM_CHAIN_ID
e DEFAULT_ETH_JSONRPC_URL
. Vamos mudá-los para 1
,'0x1'
e COINBASE_URL
respectivamente. Isto porque estaremos interagindo com a Mainnet Ethereum, e não com a Testnet Ropsten.
Em seguida, podemos apagar a linha que declara a variável DONATION_ADDRESS
, pois não a utilizaremos.
Agora vamos adicionar um pequeno código próprio.
Todo o código antes da declaração de App deve agora ser parecido com o seguinte
import React, { useEffect, useState } from 'react';
import './App.css';
import CoinbaseWalletSDK from '@coinbase/wallet-sdk'
import Web3 from 'web3';
// Credenciais da Coinbase
const COINBASE_URL = {SEU_API_ENDPOINT};
const USERNAME = {SEU_USERNAME};
const PASSWORD = {SUA_SENHA};
// Criar os títulos
const STRING = `${USERNAME}:${PASSWORD}`;
const BASE64STRING = Buffer.from(STRING).toString('base64');
const HEADERS = new Headers ({
'Content-Type':'application/json',
'Authorization':`Basic ${BASE64STRING}`
});
// Inicialização da Carteira da Coinbase
const APP_NAME = 'coinbase-wallet-example';
const APP_LOGO_URL = './coinbase-logo.png';
const DEFAULT_ETH_JSONRPC_URL = COINBASE_URL;
const DEFAULT_CHAIN_ID = 1; // 1=Ethereum (mainnet), 3=Ropsten, 5=Gorli
const DEFAULT_ETHEREUM_CHAIN_ID = '0x1'; // Deve corresponder a DEFAULT_CHAIN_ID acima, mas com 0x no início
Nota: Certifique-se de adicionar seu próprio Endpoint de API, Nome de Usuário e Senha no código acima.
3.b. Variáveis de Estado React
Adicione várias novas variáveis de estado React e exclua a variável ResponseMessage. Nossa seção de Variáveis de Estado deve agora ficar semelhante a isso:
// Variáveis de Estado React
const [isWalletConnected, setIsWalletConnected] = useState(false);
const [account, setAccount] = useState();
const [walletSDKProvider, setWalletSDKProvider] = useState();
const [web3, setWeb3] = useState();
const [nftAddress, setNftAddress] = useState();
const [ownedNFTs, setOwnedNFTs] = useState(0);
const [nftContractName, setNftContractName] = useState();
const [imageSource, setImageSource] = useState([]);
const [displayNFTs, setDisplayNFTs] = useState(false);
3.c. Criar Novas Funções - Chamadas API Avançadas do Coinbase Cloud Node
O resto do código até a função donate não precisa mudar, a menos que você queira mudar a mensagem 'Successfully switched to Ropsten Network'
para 'Successfully switched to Ethereum Mainnet'
para ser mais preciso.
Em seguida, podemos apagar a função donate em sua totalidade, pois não a utilizaremos mais. Assim, resta apenas o html. Entretanto, antes de chegarmos a isso, vamos adicionar algumas novas funções.
Primeiro, adicione a função para obter o nome da coleção NFT e verificar a conta conectada para ver quantos NFTs da coleção eles possuem:
// Função para obter o Contrato NFT e o saldo NFT na conta vinculada
const getNftContract = async () => {
setDisplayNFTs(false);
const NFT_ADDRESS = document.querySelector('#nftContract').value;
setNftAddress(NFT_ADDRESS);
try {
//Obter Metadados do Contrato NFT
let response = await fetch(COINBASE_URL, {
method: 'POST',
headers: HEADERS,
body: JSON.stringify({
'id':1,
'jsonrpc':'2.0',
'method':'coinbaseCloud_getTokenMetadata',
'params': {
'contract': NFT_ADDRESS,
'blockchain':'Ethereum',
'network':'Mainnet'
}
})
})
let data = await response.json();
setNftContractName(data.result.tokenMetadata.name);
// Obter o saldo de NFT na conta
response = await fetch(COINBASE_URL, {
method: 'POST',
headers: HEADERS,
body: JSON.stringify({
'id':2,
'jsonrpc':'2.0',
'method':'coinbaseCloud_getBalances',
'params': {
'addressAndContractList': [
{
'address':account,
'contract':NFT_ADDRESS
}
],
'blockchain':'Ethereum',
'network':'Mainnet'
}
})
})
data = await response.json();
let value = data.result.balances[0].tokenBalances[0].amount;
value = web3.utils.hexToNumber(value);
setOwnedNFTs(value);
} catch (error) {
console.error(error);
}
}
Vamos percorrer este código para que possamos entender o que está acontecendo.
Primeiro, estamos definindo a exibição da variável de estado displayNFTs
como false
, para que quando entrarmos em um novo endereço de contrato, ela reinicie nossa interface. (Mudaremos o html para isso depois).
Em seguida, estamos obtendo o endereço do contrato NFT a partir da entrada do usuário e definindo-o para nossa variável de estado nft_Address
.
Em seguida, fazemos duas solicitações para a API Avançada do Coinbase Cloud Node usando nossas variáveis COINBASE_URL
, HEADERS
, e NFT_ADDRESS
e definimos nossas variáveis de estado nftContractName
e ownedNFT
com dados das respostas. Note que estamos chamando os métodos de API Avançada coinbaseCloud_getTokenMetadata e coinbaseCloud_getBalances.
3.d. Criar novas funções - Adicionar campos de entrada
Fantástico. A seguir acrescentaremos uma função para criar campos de entrada com base em quantos NFTs a conta possui da coleção:
// Adicionar campos de entrada com base em quantos NFTs a conta possui
const addFields = () => {
return Array.from(
{ length: ownedNFTs },
(_, i) => (
<div key={`input-${i}`}>
<input
type='text'
id={`input-${i}`}
/>
</div>
)
);
}
3.e. Criar novas funções - Obter imagens do NFT
E a última função que adicionaremos é a de consultar a API NFT da Coinbase para retornar os URLs das imagens do NFT com base nas IDs do NFT que o usuário adiciona e carregá-las no vetor de variáveis de estado imageSource. Em seguida, definimos a variável de estado displayNFTs para verdadeira:
const getImages = async () => {
//Função para obter a imagem do NFT
const nftIDs = [];
const imageUrls = [];
const newURLs = [];
// Adicionar as IDs dos usuários do NFT ao vetor a partir dos campos de entrada
for (let i = 0; i < ownedNFTs; i++) {
nftIDs.push(document.querySelector(`#input-${i}`).value);
imageUrls.push('https://mainnet.ethereum.coinbasecloud.net/api/nft/v2/contracts/' + nftAddress + '/tokens/' + (`${nftIDs[i]}`) + '?networkName=ethereum-mainnet');
try {
let response = await fetch(imageUrls[i], {
method: 'GET',
headers: HEADERS
})
let data = await response.json();
let url = data.token.imageUrl.cachedPathSmall;
newURLs.push(url);
} catch (error) {
console.log(error);
}
}
setImageSource(newURLs);
setDisplayNFTs(true);
}
E então temos todo o JavaScript fora do caminho. Agora vamos mudar a parte html
do nosso código React para exibir tudo corretamente.
3.f. Mudando o HTML
Faremos várias mudanças no html para que ele exiba tudo o que precisamos. A parte html de seu código deve se parecer com o seguinte:
return (
<div className="App">
<header className="App-header">
<img src={APP_LOGO_URL} className="App-logo" alt="logo" />
{isWalletConnected ? (
<>
<h4>Mostre seus NFTs!</h4>
<p>Conta conectada {account}</p>
<p>Por favor, entre com um contrato de NFTt</p>
<div>
<input
type='string'
id='nftContract'
defaultValue={'0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D'}
/>
</div>
<br></br>
<div>
<button onClick={getNftContract} id="getNfts" type="button">
Verifique Contract
</button>
<br></br>
{nftContractName &&
<p>Você tem NFTs {ownedNFTs} na coleção {nftContractName}</p>
}
{!displayNFTs && ownedNFTs > 0 &&
<div id='imageDiv'>
<p>Por favor, entre com os IDs das NFTs</p>
{addFields()}
<br></br>
<button onClick={getImages} id='getImages' type='button'>
Obtenha NFTs
</button>
<br></br>
</div>
}
{displayNFTs && imageSource.map((image) => (
<img key={image} src={image}/>
))}
</div>
</>
) : (
<button onClick={checkIfWalletIsConnected} id="connect" type="button">
Conecte a Carteira
</button>
)}
</header>
</div>
);
}
Há algumas coisas a serem observadas no código acima. Primeiro, estamos fornecendo um endereço padrão do contrato NFT, caso o usuário não tenha um. Neste caso, é o endereço do contrato do Bored Ape Yacht Club.
Nosso botão Check Contract
chama a função getNftContract
e então mostra quantos NFTs a conta conectada possui no endereço do contrato, e também o nome da coleção.
Se o usuário possui NFTs do endereço do contrato fornecido, a função addFields
é chamada e um número de campos de entrada aparecerá com base em quantos eles possuem.
Finalmente, o botão Get NFTs
chamará a função getImages
e o próximo código irá iterar através da matriz imageSource para exibir as imagens dos URLs do NFT que elas contêm.
4. Veja Isto em Ação
É isso aí! Se tudo foi digitado corretamente e você forneceu seu próprio Endpoint da API do Coinbase Node, nome de usuário e senha, você deve ter um projeto que funcione como o seguinte GIF:
Todo o código fonte para este projeto deve se parecer com o seguinte:
import React, { useEffect, useState } from 'react';
import './App.css';
import CoinbaseWalletSDK from '@coinbase/wallet-sdk'
import Web3 from 'web3';
// Credenciais da Coinbase
const COINBASE_URL = {SEU_API_ENDPOINT};
const USERNAME = {SEU_USERNAME};
const PASSWORD = {SUA_SENHA};
// Criar os títulos
const STRING = `${USERNAME}:${PASSWORD}`;
const BASE64STRING = Buffer.from(STRING).toString('base64');
const HEADERS = new Headers ({
'Content-Type':'application/json',
'Authorization':`Basic ${BASE64STRING}`
});
//Inicialização da Carteira da Coinbase
const APP_NAME = 'coinbase-wallet-example';
const APP_LOGO_URL = './coinbase-logo.png';
const DEFAULT_ETH_JSONRPC_URL = COINBASE_URL;
const DEFAULT_CHAIN_ID = 1; // 1=Ethereum (mainnet), 3=Ropsten, 5=Gorli
const DEFAULT_ETHEREUM_CHAIN_ID = '0x1'; // Deveria corresponder a DEFAULT_CHAIN_ID acima, mas com 0x no início
const App = () => {
// Variáveis de Estado React
const [isWalletConnected, setIsWalletConnected] = useState(false);
const [account, setAccount] = useState();
const [walletSDKProvider, setWalletSDKProvider] = useState();
const [web3, setWeb3] = useState();
const [nftAddress, setNftAddress] = useState();
const [ownedNFTs, setOwnedNFTs] = useState(0);
const [nftContractName, setNftContractName] = useState();
const [imageSource, setImageSource] = useState([]);
const [displayNFTs, setDisplayNFTs] = useState(false);
useEffect(() => {
const coinbaseWallet = new CoinbaseWalletSDK({
appName: APP_NAME,
appLogoUrl: APP_LOGO_URL,
});
const walletSDKProvider = coinbaseWallet.makeWeb3Provider(
DEFAULT_ETH_JSONRPC_URL,
DEFAULT_CHAIN_ID
);
setWalletSDKProvider(walletSDKProvider);
const web3 = new Web3(walletSDKProvider);
setWeb3(web3);
}, []);
const checkIfWalletIsConnected = () => {
if (!window.ethereum) {
console.log(
'Nenhum objeto da Ethereum encontrado. Favor instalar a extensão da Carteira Coinbase ou similar.'
);
web3.setProvider(walletSDKProvider.enable());
return;
}
console.log('Encontrado um objeto da Ethereum:', window.ethereum);
connectWallet();
};
const connectWallet = async () => {
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts',
});
if (!accounts.length) {
console.log('Nenhuma conta autorizada encontrada');
return;
}
if (accounts.length) {
const account = accounts[0];
console.log('Encontrada uma conta autorizada:', account);
setAccount(account);
try {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: DEFAULT_ETHEREUM_CHAIN_ID }],
});
console.log('Mudança com sucesso para a "Rede Ropsten".);
} catch (error) {
console.error(error);
}
}
setIsWalletConnected(true);
};
// Função para obter o Contrato NFT e o saldo NFT na conta vinculada
const getNftContract = async () => {
setDisplayNFTs(false);
const NFT_ADDRESS = document.querySelector('#nftContract').value;
setNftAddress(NFT_ADDRESS);
try {
// Obter Metadados do Contrato NFT
let response = await fetch(COINBASE_URL, {
method: 'POST',
headers: HEADERS,
body: JSON.stringify({
'id':1,
'jsonrpc':'2.0',
'method':'coinbaseCloud_getTokenMetadata',
'params': {
'contract': NFT_ADDRESS,
'blockchain':'Ethereum',
'network':'Mainnet'
}
})
})
let data = await response.json();
setNftContractName(data.result.tokenMetadata.name);
// Obter o saldo do NFT na conta
response = await fetch(COINBASE_URL, {
method: 'POST',
headers: HEADERS,
body: JSON.stringify({
'id':2,
'jsonrpc':'2.0',
'method':'coinbaseCloud_getBalances',
'params': {
'addressAndContractList': [
{
'address':account,
'contract':NFT_ADDRESS
}
],
'blockchain':'Ethereum',
'network':'Mainnet'
}
})
})
data = await response.json();
let value = data.result.balances[0].tokenBalances[0].amount;
value = web3.utils.hexToNumber(value);
setOwnedNFTs(value);
} catch (error) {
console.error(error);
}
}
// Adicionar campos de entrada com base em quantos NFTs a conta possui
const addFields = () => {
return Array.from(
{ length: ownedNFTs },
(_, i) => (
<div key={`input-${i}`}>
<input
type='text'
id={`input-${i}`}
/>
</div>
)
);
}
const getImages = async () => {
// Função para obter a imagem do NFT
const nftIDs = [];
const imageUrls = [];
const newURLs = [];
// Adicionar IDs dos usuários do NFT ao vetor a partir dos campos de entrada
for (let i = 0; i < ownedNFTs; i++) {
nftIDs.push(document.querySelector(`#input-${i}`).value);
imageUrls.push('https://mainnet.ethereum.coinbasecloud.net/api/nft/v2/contracts/' + nftAddress + '/tokens/' + (`${nftIDs[i]}`) + '?networkName=ethereum-mainnet');
try {
let response = await fetch(imageUrls[i], {
method: 'GET',
headers: HEADERS
})
let data = await response.json();
let url = data.token.imageUrl.cachedPathSmall;
newURLs.push(url);
} catch (error) {
console.log(error);
}
}
setImageSource(newURLs);
setDisplayNFTs(true);
}
return (
<div className="App">
<header className="App-header">
<img src={APP_LOGO_URL} className="App-logo" alt="logo" />
{isWalletConnected ? (
<>
<h4>Mostre seus NFTs!</h4>
<p>Conta Conectada: {account}</p>
<p>Por favor, entre com um contrato NFT</p>
<div>
<input
type='string'
id='nftContract'
defaultValue={'0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D'}
/>
</div>
<br></br>
<div>
<button onClick={getNftContract} id="getNfts" type="button">
Verifique o Contrato
</button>
<br></br>
{nftContractName &&
<p>Você tem NFTs{ownedNFTs} na coleção {nftContractName} collection</p>
}
{!displayNFTs && ownedNFTs > 0 &&
<div id='imageDiv'>
<p>Por favor, entre com os IDs dos NFTs</p>
{addFields()}
<br></br>
<button onClick={getImages} id='getImages' type='button'>
Obtenha os NFTs
</button>
<br></br>
</div>
}
{displayNFTs && imageSource.map((image) => (
<img key={image} src={image}/>
))}
</div>
</>
) : (
<button onClick={checkIfWalletIsConnected} id="connect" type="button">
Conecte a Carteira
</button>
)}
</header>
</div>
);
}
export default App;
Conclusão
Desde 2021, tenho tentado viver de acordo com a seguinte declaração de missão, que sinto que pode ser aplicada a qualquer profissional de tecnologia:
"Concentre seu tempo no fornecimento de recursos/funcionalidade que amplie o valor de sua propriedade intelectual. Alavanque estruturas, produtos e serviços para tudo o mais". J. Vester
Os desenvolvedores Web3 se encontram em uma posição semelhante à qual eu estava no início de minha carreira, navegando entre as esperanças e sonhos da revolução do PC. Com o poder da computação duplicando a cada 18 a 24 meses, parecia que nenhuma característica ou funcionalidade estava fora do escopo. No entanto, todos nós aprendemos rapidamente que há mais do que apenas a potência da CPU para impulsionar as decisões.
Os desenvolvedores da Web3 precisam do conjunto certo de ferramentas, estruturas, produtos e serviços para ajudá-los a ter sucesso. Nesta publicação, exploramos o Coinbase Cloud Node e as APIs NFT que aderem fortemente à minha declaração de missão pessoal. Dentro de um conjunto razoável de lógica de programa, fomos capazes de usar com sucesso essas APIs para ler dados NFT e até mesmo exibir os NFTs do usuário. O tempo economizado ao aproveitar as opções do Coinbase Cloud permitirá que os desenvolvedores se concentrem em suas principais metas e objetivos.
Se você estiver interessado no código fonte para este artigo, ele pode ser encontrado no seguinte URL:
https://gitlab.com/johnjvester/coinbase-node-nft-api-tutorial
A lei de Moore começou a desacelerar em 2010 e a maioria concorda que alcançará seu fim de vida em cerca de três anos - devido a limitações físicas. Isto provavelmente abrirá o caminho para novas soluções para pavimentar o caminho - como computação quântica, inteligência artificial e aprendizagem de máquinas. Isto não é muito diferente em como a Web3 está se tornando uma opção atraente para atender às necessidades comerciais.
Tenha um ótimo dia!
Este artigo foi escrito por John Vester e traduzido por Fátima Lima. Seu original pode ser lido aqui.
Oldest comments (0)