Youtube video: https://youtu.be/vHEhkRqQcdU
Start random chats with strangers based on interests, and create direct chats with someone you know from a simple interface! π
Hackathon: LUKSO Build UP! #1: Social & DAOs - Chat DApp build of an encrypted Chat DApp on Lukso Network using Scaffold-ETH-NextJS framework.
A Chat Dapp that is built on the Lukso network and leverages the Lukso Standards Proposals(LSPs) and Universal Profiles to create a highly decentralized chat application that is blockchain based.
- Random Chat based on Interests
- Direct Chat
- Encrypted messages
DOmagle is implemented by using UP and Vault standards
For DOmagle We create a common UP and Vault using the lspFactory.
- Deploy.tsx
/* ---------------------
* CREATE UP
* ---------------------*/
const lspFactory = new LSPFactory(RPC_ENDPOINT, {
deployKey: account.privateKey,
chainId: CHAIN_ID,
});
async function createUniversalProfile(): any {
const deployedContracts = await lspFactory.UniversalProfile.deploy({
controllerAddresses: [account.address], // our EOA that will be controlling the UP
lsp3Profile: {
name: "DOmagle",
description: "DOmagle main common profile",
tags: ["Public Profile cool test"],
links: [
{
title: "DOmagle",
url: "https://domagle.eth",
},
],
},
LSP4TokenName: "DOM",
});
return deployedContracts;
}
const output = await createUniversalProfile();
const upAddress = output["LSP0ERC725Account"]["address"] as string;
// 1. DEPLOY VAULT
const vault = new Vault__factory(commonSigner as Signer);
// 2. SET THE UP AS OWNER
const deployedVault = await vault.deploy(upAddress);
const owner = await deployedVault.owner();
const vaultAddress = deployedVault.address;
console.log("upAddress: ", upAddress);
console.log("vaultAddress: ", vaultAddress);
console.log("vault: owner ", owner);
};
Then we grant users addresess permissions to interact with the vault.
- grantPermission.ts
async function grantPersmission(address): Promise<boolean> {
const UP: ethers.Contract = global.UP;
const KM: ethers.Contract = global.KM;
const erc725: ERC725 = global.erc725;
const walletSigner: Signer = global.walletSigner;
try {
/** ----------------------
* set the call permission
* ---------------------*/
const beneficiaryAddress = address; // EOA address of an exemplary person
const beneficiaryPermissions = erc725?.encodePermissions({
// ADDPERMISSIONS: true,
CALL: true,
// CHANGEOWNER: true,
// CHANGEPERMISSIONS: true,
// DELEGATECALL: true,
// DEPLOY: true,
// SETDATA: true,
// SIGN: true,
// STATICCALL: true,
// SUPER_CALL: true,
// SUPER_DELEGATECALL: true,
// SUPER_SETDATA: true,
// SUPER_STATICCALL: true,
// SUPER_TRANSFERVALUE: true,
// TRANSFERVALUE: true,
});
// Encode the data key-value pairs of the permissions to be set
const data = erc725?.encodeData({
keyName: "AddressPermissions:Permissions:<address>",
dynamicKeyParts: beneficiaryAddress,
value: beneficiaryPermissions,
});
const payload = UP.interface.encodeFunctionData("setData(bytes32,bytes)", [data.keys[0], data.values[0]]);
// Send the transaction via the Key Manager contract
const tx = await KM.connect(walletSigner).execute(payload, { gasLimit: 10000000 }); // <---- call the execute on key manager contract
const rcpt = await tx.wait();
/** ----------------------
* Add allowed address
* ---------------------*/
const allowedAddressData = erc725?.encodeData({
keyName: "AddressPermissions:AllowedAddresses:<address>",
dynamicKeyParts: address,
value: [VAULT_ADDRESS],
});
const allowedAddressDataPayload = UP.interface.encodeFunctionData("setData(bytes32[],bytes[])", [
allowedAddressData?.keys,
allowedAddressData?.values,
]);
const tx1 = await KM.connect(walletSigner).execute(allowedAddressDataPayload, { gasLimit: 10000000 }); // <---- call the execute on key manager contract
const rcpt1 = await tx1.wait();
return true;
} catch (error) {
console.log("error: ", error);
return false;
}
}
On the backend we create a dynamic key for both parties
- connectUser.ts
const addresses = [toAddress, userAddress].sort();
connectUsers[userAddress].users = addresses;
matchedAdress = userAddress;
// create a dynamic uinque key
const dynamicKey = ERC725.encodeKeyName(KEY_NAME, [...addresses]);
connectUsers[userAddress].dynamicKey = dynamicKey;
connectUsers[userAddress].status = "MATCH";
We create and push chatSchema
- ChatView.tsx | DirectChatView.tsx
const KEY_NAME = "chat:<string>:<string>";
const chatSchema = {
name: "chat:<string>:<string>",
key: "0x",
keyType: "Mapping",
valueType: "string[]",
valueContent: "String",
};
erc725schema.push(chatSchema);
Encode and Decode the chat mesages (we use eth-crypto for encryption in the backend)
const msgData = {
address: address,
message: chatMessage,
};
const reqData = {
type: "ENCRYPT",
msgData,
};
// encrypt the data
const { data } = await axios.post(`${BASE_URL}/api/encryptDecryptMsg`, {
...reqData,
});
const encryptedData = data.encryptedData;
const encodedChatData = erc725?.encodeData({
keyName: KEY_NAME,
dynamicKeyParts: [...users],
value: [...oldData, encryptedData],
});
const setDataVaultPayload = vault.interface.encodeFunctionData("setData(bytes32[],bytes[])", [
encodedChatData?.keys,
encodedChatData?.values,
]);
const vaultExecutePayload = vault.interface.encodeFunctionData("execute", [
0,
vault.address as string,
0,
setDataVaultPayload,
]);
// on execute call
const tx = await km?.connect(signer as Signer).execute(vaultExecutePayload, { gasLimit: 10000000 }); // <---- call the execute on key manager contract
const rcpt = await tx.wait();
- Find a Random Chat based on interests
- Then wait for a match
- Start your conversation with the stranger
- When someone gives you their address, you can chat directly
- πΒ Scaffold-Eth-next Typescript
- erc725.js
- lsp-contracts.js
- eth-crypto
Prerequisites: Node (v16 LTS) plus Yarn and Git
clone/fork πΒ Scaffold-Eth-NextJS: DOmagle Build
git clone https://github.com/Naim-Bijapure/D-Chat.git
install packages and setup Foundry:
cd D-Chat
yarn install
yarn setup
Start your π·β Anvil chain:
yarn chain
π± Remember to generate your account with yarn generate
, it will be generated in packages/foundry-ts/generated/account.json
in a second terminal window,:
cd D-Chat
yarn deploy
in a third terminal window, start your π± frontend:
π Edit packages/next-ts/components/configs/appContract.config.ts
to enable testing on localhost
π Edit packages/next-ts/constants/index.ts
to change your backend
cd D-Chat
yarn run dev
in a fourth terminal window, π° start the backend:
cd D-Chat/backend
yarn serve
π± Open http://localhost:3000 to see the app
Note: To test locally, you need to deploy UP and Vault, for that go to http://localhost:3000/Deploy and copy UP and Vault addresses from broweser console, and edit packages/backend/constants/index.ts
with the correspoding values of UP_ADDRESS
, VAULT_ADDRESS
and RCP_URL
- Implementing Relayer
- Inttegrating Events with notification services
- Bug Fixes :)
π° Use a faucet like https://faucet.l16.lukso.network/ to fund your deployer address
π Run yarn deploy to deploy to the network of choice
π¬ Inspect the block explorer for the network you deployed to... make sure your contract is there.
π¦ Run yarn vercel deploy.
yarn vercel:deploy
Register as a builder here and start on some of the challenges and build a portfolio.
Join the telegram support chat π¬ to ask questions and find others building with π scaffold-eth!
π Please check out our Gitcoin grant too!