Skip to content

Instantly share code, notes, and snippets.

@jeasonstudio
Last active June 3, 2024 07:02
Show Gist options
  • Save jeasonstudio/92fa28c29cb7b0c07d059c6b78e3fccb to your computer and use it in GitHub Desktop.
Save jeasonstudio/92fa28c29cb7b0c07d059c6b78e3fccb to your computer and use it in GitHub Desktop.
Automatic interactive with ZAN and Artela testnet.
// Usage: `PRIVATE_KEY=0xfffff...fff node artela-zan.js`
import { privateKeyToAccount } from 'viem/accounts';
import { generateSiweNonce, createSiweMessage } from 'viem/siwe';
import {
defineChain,
createWalletClient,
createPublicClient,
http,
} from 'viem';
// Make sure gas fee is enough
const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const endpoint = 'https://zan.top/v1';
const contractAddress = '0x02fDC70Bf4E54008BE2674859B1e6541127DdaC4';
const artela = defineChain({
id: 11822,
name: 'Artela Testnet',
network: 'artela-testnet',
nativeCurrency: {
symbol: 'ART',
name: 'ART',
decimals: 18,
},
rpcUrls: {
default: {
http: ['https://betanet-rpc1.artela.network'],
},
},
blockExplorers: {
default: {
name: 'ArtelaScan',
url: 'https://betanet-scan.artela.network',
},
},
testnet: true,
});
const abi = [
{
inputs: [
{
internalType: 'bytes',
name: 'signature',
type: 'bytes',
},
],
name: 'mint',
outputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [
{
internalType: 'address',
name: 'sender',
type: 'address',
},
],
name: 'getHash',
outputs: [
{
internalType: 'bytes32',
name: '',
type: 'bytes32',
},
],
stateMutability: 'view',
type: 'function',
},
];
const cookies = [];
const request = async (url, options) =>
fetch(`${endpoint}${url}`, {
...options,
headers: { ...(options?.headers ?? {}), cookie: cookies.join('; ') },
})
.then((res) => {
cookies.push(...res.headers.getSetCookie());
return res.json();
})
.then((result) => {
if (result.success) {
return result.data;
}
throw new Error(JSON.stringify(result.errorMessage));
});
// generate siwe message
const nonce = await request(
`/api/chain-account/get-nonce?chainAddress=${account.address}`
);
const message = createSiweMessage({
domain: 'zan.top',
address: account.address,
statement: 'Sign in with Artela to ZAN.top',
uri: 'https://zan.top/',
version: '1',
chainId: artela.id,
nonce,
});
// sign message and verify
const signature = await account.signMessage({ message });
await request(
`/api/chain-account/verify?message=${encodeURIComponent(
message
)}&signature=${signature}`,
{ method: 'POST' }
);
// fetch kyt api
await request(`/api/activity/kyt/${account.address}/risk?ecosystem=eth`);
// get userinfo
const user = await request(
`/api/chain-account/get-address-info?chainAddress=${account.address}`
);
// check if user is verified
if (user?.address !== account.address || !user?.isVerified || !user?.isKyt) {
throw new Error('Something went wrong!');
}
const hash = await createPublicClient({
chain: artela,
transport: http(),
}).readContract({
address: contractAddress,
abi,
functionName: 'getHash',
args: [account.address],
});
const sign = await request(
`/api/chain-account/get-mint-signature?hash=${hash}`
);
const txHash = await createWalletClient({
account,
chain: artela,
transport: http(),
}).writeContract({
address: contractAddress,
abi,
functionName: 'mint',
args: [sign],
});
console.log(`Mint success!`);
console.log(
`Open in ArtelaScan: https://betanet-scan.artela.network/tx/${txHash}`
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment