Using your Embedded Wallet
Once the user has been authenticated, you can now utilize common web3 functions to interact with the blockchain - completely seamlessly.
- Get Wallet Address: Access the wallet linked to the user's authenticated account. This wallet serves as the gateway to all account functions.
- Sign Messages: Signing a message using the embedded wallet.
- Send Transactions: After a user has been authenticated, use the WaaS SDK to send transactions using crafted EVM calldata.
Install SDK
If you have not already done so, make sure the Embedded Wallet SDK is installed in your project:
pnpm install @0xsequence/waas
Get Wallet Address
Each user's wallet address is unique, cannot be changed, and is 42 characters long, starting with 0x
:
import { SequenceWaaS } from "@0xsequence/waas";
const sequence = new SequenceWaaS(
{
projectAccessKey: `${process.env.VITE_PROJECT_ACCESS_KEY}`,
waasConfigKey: `${process.env.VITE_WAAS_CONFIG_KEY}`,
network: "arbitrum-nova",
}
);
const { wallet } = await sequence.signIn({ idToken }, "Session name")
const address = await sequence.getAddress();
console.log(address == wallet) // true
console.log(address)
0xE4b10c53aa75E19E088cfDD0cff7D46a0E4206F0
Sign Messages
Wallets can sign messages, which can be validated both onchain and offchain:
import { SequenceWaaS } from "@0xsequence/waas";
const sequence = new SequenceWaaS(
{
projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`,
waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`,
network: "arbitrum-nova",
}
);
await sequence.signIn({ idToken }, "Session name");
const signature = await sequence.signMessage({
chainId: 42170,
message: "Hello world",
});
console.log(signature);
{
"code": "signedMessage",
"data": {
"message": "0x48656c6c6f20776f726c64",
"signature": "0x0100010000000002012128ff2dd168dc250dc3da93db3131f737e6961a0000fe0100030000000006010001000074000197013331090a763fc7ef2216502cfbff5d855530f977a0ee6db3615722ed9bad498781d8ed72d52b5c9717708ac757f7789c9567e5468566179bd03f72d1fc7b1c010400002c01011111b16c6268897233eddea98a041b326b0faef2010122229ce37ccfee1cbab2b743b22c314b5667cf1a06020001000074000100deb9091f5beb1ebd8d91a1b81e562a70cdb3a1cdafc5e61087b18d1c221c570754ecbe056bdef5f82c388a9bf53f074521aeaf5afdeed3a2ba70adb89362631b010400002c0101444444444444444444444444444444444444444401015555555555555555555555555555555555555555030100a5a91b133336e5ef1c7e23c13974535018fab1c0"
}
}
Send Transactions
All wallets can send transactions right after creation. No extra steps are required to create the wallet, as all users have a wallet by default.
Raw transaction
- Immediate Transactions: Wallets are ready to send transactions immediately upon creation.
- Raw Transactions: Specify transaction parameters such as recipient, value, and data. Gas limits and nonce are managed automatically.
- Network Requirements: Transactions require specifying a
chainId
for the intended network., for example1
for Ethereum mainnet,42161
for Arbitrum, etc.
import { Sequence, isSentTransactionResponse } from "@0xsequence/waas";
const sequence = new SequenceWaaS(
{
projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`,
waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`,
network: "arbitrum-nova",
}
);
await sequence.signIn({ idToken }, "Session name");
const tx = await sequence.sendTransaction({
chainId: 42161,
transactions: [
{
to: "0x27CabC9700EE6Db2797b6AC1e1eCe81C72A2cD8D",
value: "200000000000000000000", // 200 ETH
data: "0x9fa2b3c4",
},
],
});
if (isSentTransactionResponse(tx)) {
console.log(tx);
}
{
"code": "transactionReceipt",
"data": {
"txHash": "0xf2e9f728abd65089f25efda5852e605ced377f4e2c89dbf143b124623ed09b2c",
"metaTxHash": "acc36ed4ef40db74137266e48d863083a5c7e85e2735d69adafcb5b362b6cfc0",
"nativeReceipt": { ... },
"receipt": { ... },
"request": { ... },
"simulations": [ ... ],
}
}
Send ERC20 Tokens
Helper methods are available for common operations, such as sending ERC20 tokens. This automatically handles the data
field of the transaction:
import { Sequence, isSentTransactionResponse } from "@0xsequence/waas";
const sequence = new SequenceWaaS(
{
projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`,
waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`,
network: "mumbai",
},
defaults.TEST
);
await sequence.signIn({ idToken }, "Session name");
const tx = await sequence.sendERC20({
chainId: 42161,
token: "0x6b175474e89094c44da98b954eedeac495271d0f", // DAI
to: "0x27CabC9700EE6Db2797b6AC1e1eCe81C72A2cD8D", // Recipient
value: "200000000000000000000", // 200 DAI
});
if (isSentTransactionResponse(tx)) {
console.log(tx);
}
{
"code": "transactionReceipt",
"data": {
"txHash": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3",
"metaTxHash": "01a087979dccbbc49a45b72d987e5651d65bd97349ccbfdd601b0b7beee9ddc4",
"nativeReceipt": { ... },
"receipt": { ... },
"request": { ... },
"simulations": [ ... ],
}
}
Send ERC721 Tokens
Sending ERC721 tokens has a helper method. This automatically handles the data
field of the transaction:
import { Sequence, isSentTransactionResponse } from "@0xsequence/waas";
const sequence = new SequenceWaaS(
{
projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`,
waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`,
network: "arbitrum-nova",
}
);
await sequence.signIn({ idToken });
const tx = await sequence.sendERC721({
chainId: 42161,
token: "0xF87E31492Faf9A91B02Ee0dEAAd50d51d56D5d4d", // Decentraland LAND
to: "0x27CabC9700EE6Db2797b6AC1e1eCe81C72A2cD8D", // Recipient
id: "33347671958251969419410711528313284722562", // Asset ID
});
if (isSentTransactionResponse(tx)) {
console.log(tx);
}
{
"code": "transactionReceipt",
"data": {
"txHash": "0x4936962d9972a70bffc27f376f55d9c60c12e762819fa6384fdb466664122b6e",
"metaTxHash": "e6513a60b63359a365f0d3f05744d89823278ec829fc5cb4d275bb815d0f5887",
"nativeReceipt": { ... },
"receipt": { ... },
"request": { ... },
"simulations": [ ... ],
}
}
Send ERC1155 Tokens
Sending ERC1155 tokens is also supported:
import { Sequence, isSentTransactionResponse } from "@0xsequence/waas";
const sequence = new SequenceWaaS(
{
projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`,
waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`,
network: "arbitrum-nova",
}
);
await sequence.signIn({ idToken });
const tx = await sequence.sendERC1155({
chainId: 137,
token: "0x631998e91476da5b870d741192fc5cbc55f5a52e", // Skyweaver assets
values: [
{
id: "66547", // Asset ID
value: "200", // Amount for this asset
},
{
id: "68572",
value: "1000",
},
],
});
Call any Contract
Use callContract
to interact with any contract method, either through a function signature or ABI, supporting both named and positional arguments.
Function Signature
Providing a function signature is the easiest way to call a contract method, as it doesn't require an ABI. The function signature can be provided with named parameters or positional parameters.
Named Arguments
const tx = await sequence.callContract({
to: "0x503388C73Ca663eA34e103c11C9F47C9433af471", // Contract address
abi: "mint(address to, uint256 tokenId)", // Function signature
func: "mint", // Function name
args: {
to: "0xf439e432d54c2Bf5518A1901D3791070d4192986",
tokenId: "1",
},
value: 0, // Value to send
});
Positional Arguments
Notice that passing a named function signature with positional arguments is allowed.
const tx = await sequence.callContract({
to: "0x503388C73Ca663eA34e103c11C9F47C9433af471", // Contract address
abi: "mint(address,uint256)", // Function signature
func: "mint", // Function name
args: ["0xf439e432d54c2Bf5518A1901D3791070d4192986", "1"],
value: 0, // Value to send
});
ABI
Providing an ABI is more verbose, but allows for more flexibility, as a single ABI can be used to call multiple methods. ABIs support named arguments and positional arguments.
const abi = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]`;
const tx = await sequence.callContract({
to: "0x6b175474e89094c44da98b954eedeac495271d0f", // Contract address
abi: abi, // ABI
func: "transfer", // Function name
args: {
_to: "0xf439e432d54c2Bf5518A1901D3791070d4192986",
_value: "1",
},
value: 0, // Value to send
});