Merge pull request #477 from kinode-dao/dr/update-kimap

Update kimap contract
This commit is contained in:
doria 2024-08-09 18:03:52 +03:00 committed by GitHub
commit ebd5374c95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 2270 additions and 3167 deletions

View File

@ -2,9 +2,9 @@ import { parseAbi } from "viem";
export { encodeMulticalls, encodeIntoMintCall } from "./helpers";
export const KINOMAP: `0x${string}` = "0x7290Aa297818d0b9660B2871Bb87f85a3f9B4559";
export const KINOMAP: `0x${string}` = "0xAfA2e57D3cBA08169b416457C14eBA2D6021c4b5";
export const MULTICALL: `0x${string}` = "0xcA11bde05977b3631167028862bE2a173976CA11";
export const KINO_ACCOUNT_IMPL: `0x${string}` = "0x58790D9957ECE58607A4b58308BBD5FE1a2e4789";
export const KINO_ACCOUNT_IMPL: `0x${string}` = "0xd30217e86A4910f4D7cB3E73fC3CfD28a2C33e4e";
export const multicallAbi = parseAbi([

View File

@ -21,7 +21,7 @@ import './index.css'
const config = getDefaultConfig({
appName: 'Kinode App Store',
projectId: 'YOUR_PROJECT_ID',
projectId: 'KINODE_APP_STORE',
chains: [optimism],
ssr: false,
transports: {

View File

@ -21,17 +21,17 @@ wit_bindgen::generate!({
});
#[cfg(not(feature = "simulation-mode"))]
const KIMAP_ADDRESS: &'static str = "0x7290Aa297818d0b9660B2871Bb87f85a3f9B4559"; // optimism
const KIMAP_ADDRESS: &'static str = kimap::KIMAP_ADDRESS; // optimism
#[cfg(feature = "simulation-mode")]
const KIMAP_ADDRESS: &'static str = "0xEce71a05B36CA55B895427cD9a440eEF7Cf3669D"; // local
#[cfg(not(feature = "simulation-mode"))]
const CHAIN_ID: u64 = 10; // optimism
const CHAIN_ID: u64 = kimap::KIMAP_CHAIN_ID; // optimism
#[cfg(feature = "simulation-mode")]
const CHAIN_ID: u64 = 31337; // local
#[cfg(not(feature = "simulation-mode"))]
const KIMAP_FIRST_BLOCK: u64 = 114_923_786; // optimism
const KIMAP_FIRST_BLOCK: u64 = kimap::KIMAP_FIRST_BLOCK; // optimism
#[cfg(feature = "simulation-mode")]
const KIMAP_FIRST_BLOCK: u64 = 1; // local

View File

@ -53,7 +53,7 @@ pub const CHAIN_ID: u64 = 10;
#[cfg(feature = "simulation-mode")]
pub const CHAIN_ID: u64 = 31337;
#[cfg(not(feature = "simulation-mode"))]
pub const KIMAP_ADDRESS: &str = "0x7290Aa297818d0b9660B2871Bb87f85a3f9B4559";
pub const KIMAP_ADDRESS: &str = "0xAfA2e57D3cBA08169b416457C14eBA2D6021c4b5";
#[cfg(feature = "simulation-mode")]
pub const KIMAP_ADDRESS: &str = "0x0165878A594ca255338adfa4d48449f69242Eb8F";
pub const MULTICALL_ADDRESS: &str = "0xcA11bde05977b3631167028862bE2a173976CA11";

File diff suppressed because it is too large Load Diff

View File

@ -17,8 +17,8 @@
"react-icons": "^5.0.1",
"react-modal": "^3.16.1",
"react-router-dom": "^6.16.0",
"viem": "^2.15.1",
"wagmi": "^2.10.3"
"viem": "^2.19.0",
"wagmi": "^2.12.5"
},
"scripts": {
"start": "vite",

View File

@ -1,16 +1,16 @@
import { useState, useEffect } from "react";
import { Navigate, BrowserRouter as Router, Route, Routes, useParams } from 'react-router-dom';
import RegisterKnsName from "./pages/RegisterKnsName";
import CommitDotOsName from "./pages/CommitDotOsName";
import MintDotOsName from "./pages/MintDotOsName";
import SetPassword from "./pages/SetPassword";
import Login from './pages/Login'
import ResetKnsName from './pages/ResetKnsName'
import ResetDotOsName from './pages/ResetDotOsName'
import KinodeHome from "./pages/KinodeHome"
import ImportKeyfile from "./pages/ImportKeyfile";
import { UnencryptedIdentity } from "./lib/types";
import Header from "./components/Header";
function App() {
const params = useParams()
@ -35,7 +35,6 @@ function App() {
const openConnect = () => setConnectOpen(true)
const closeConnect = () => setConnectOpen(false)
useEffect(() => setAppSizeOnLoad(
(window.performance.getEntriesByType('navigation') as any)[0].transferSize
), []);
@ -109,9 +108,10 @@ function App() {
? <Navigate to="/login" replace />
: <KinodeHome {...props} />
} />
<Route path="/register-name" element={<RegisterKnsName {...props} />} />
<Route path="/commit-os-name" element={<CommitDotOsName {...props} />} />
<Route path="/mint-os-name" element={<MintDotOsName {...props} />} />
<Route path="/set-password" element={<SetPassword {...props} />} />
<Route path="/reset" element={<ResetKnsName {...props} />} />
<Route path="/reset" element={<ResetDotOsName {...props} />} />
<Route path="/import-keyfile" element={<ImportKeyfile {...props} />} />
<Route path="/login" element={<Login {...props} />} />
</Routes>

View File

@ -76,6 +76,16 @@ export const generateNetworkingKeys = async ({
]
});
const tcp_port_call =
encodeFunctionData({
abi: kinomapAbi,
functionName: 'note',
args: [
encodePacked(["bytes"], [stringToHex("~tcp-port")]),
encodePacked(["bytes"], [bytesToHex(portToBytes(tcp_port || 0))]),
]
});
const ip_address_call =
encodeFunctionData({
abi: kinomapAbi,
@ -103,6 +113,7 @@ export const generateNetworkingKeys = async ({
const calls = direct ? [
{ target: KINOMAP, callData: netkeycall },
{ target: KINOMAP, callData: ws_port_call },
{ target: KINOMAP, callData: tcp_port_call },
{ target: KINOMAP, callData: ip_address_call },
] : [
{ target: KINOMAP, callData: netkeycall },

View File

@ -3,11 +3,11 @@ import { parseAbi } from "viem";
export { generateNetworkingKeys } from "./helpers";
// move to constants? // also for anvil/optimism
export const KINOMAP: `0x${string}` = "0x7290Aa297818d0b9660B2871Bb87f85a3f9B4559";
export const KINOMAP: `0x${string}` = "0xAfA2e57D3cBA08169b416457C14eBA2D6021c4b5";
export const MULTICALL: `0x${string}` = "0xcA11bde05977b3631167028862bE2a173976CA11";
export const KINO_ACCOUNT_IMPL: `0x${string}` = "0x58790D9957ECE58607A4b58308BBD5FE1a2e4789";
export const DOTOS: `0x${string}` = "0xcf0af6048D42B2a8e18b1B062a6c4a027D8C5Ea6";
export const DOTDEV: `0x${string}` = "0x3BA6AE3eca7ca88af8BbCc8A9d8EA5e665b69Eb3";
export const KINO_ACCOUNT_IMPL: `0x${string}` = "0xd30217e86A4910f4D7cB3E73fC3CfD28a2C33e4e";
export const DOTOS: `0x${string}` = "0x4f0d377e66E4A2750A928495cE261A345e2f0557";
// export const DOTDEV: `0x${string}` = "0x3BA6AE3eca7ca88af8BbCc8A9d8EA5e665b69Eb3";
export const multicallAbi = parseAbi([
`function aggregate(Call[] calls) external payable returns (uint256 blockNumber, bytes[] returnData)`,
@ -24,3 +24,29 @@ export const mechAbi = parseAbi([
"function execute(address to, uint256 value, bytes calldata data, uint8 operation) returns (bytes memory returnData)",
"function token() external view returns (uint256,address,uint256)"
])
export const dotOsAbi = [
{
type: 'function',
name: 'commit',
stateMutability: 'nonpayable',
inputs: [
{ name: '_commit', type: 'bytes32' },
],
outputs: [],
},
{
type: 'function',
name: 'mint',
stateMutability: 'nonpayable',
inputs: [
{ name: 'who', type: 'address' },
{ name: 'name', type: 'bytes' },
{ name: 'initialization', type: 'bytes' },
{ name: 'erc721Data', type: 'bytes' },
{ name: 'implementation', type: 'address' },
{ name: 'secret', type: 'bytes32' },
],
outputs: [{ type: 'address' }],
},
] as const

View File

@ -32,7 +32,7 @@
visibility: hidden;
width: 200px;
background-color: #555;
color: #fff;
color: var(--off-white);
text-align: center;
border-radius: 6px;
padding: 5px;
@ -66,7 +66,7 @@
}
.section {
background-color: var(--white);
background-color: light-dark(var(--off-white), var(--tasteful-dark));
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 2rem;
@ -127,14 +127,14 @@
.kns-input {
flex-grow: 1;
padding: 0.5rem;
border: 1px solid #ccc;
border: 1px solid var(--gray);
border-radius: 4px 0 0 4px;
}
.kns-suffix {
padding: 0.5rem;
background-color: #f0f0f0;
border: 1px solid #ccc;
background-color: var(--gray);
border: 1px solid var(--tasteful-dark);
border-left: none;
border-radius: 0 4px 4px 0;
}
@ -146,7 +146,7 @@
}
.error-message {
color: #ff0000;
color: var(--ansi-red);
margin-top: 0.5rem;
}
@ -186,7 +186,7 @@
}
.checkbox-container:hover input~.checkmark {
background-color: #ccc;
background-color: var(--gray);
}
.checkbox-container input:checked~.checkmark {
@ -208,7 +208,7 @@
top: 5px;
width: 5px;
height: 10px;
border: solid white;
border: solid var(--off-white);
border-width: 0 3px 3px 0;
transform: rotate(45deg);
}
@ -234,5 +234,5 @@
.file-input-label:hover .button {
background-color: var(--dark-orange);
color: white;
color: var(--off-white);
}

View File

@ -26,7 +26,7 @@ window.Buffer = Buffer;
const config = getDefaultConfig({
appName: 'Kinode Register UI',
projectId: 'YOUR_PROJECT_ID',
projectId: 'KINODE_REGISTER',
chains: [optimism],
ssr: false,
transports: {

View File

@ -22,7 +22,7 @@ export interface PageProps {
pw: string,
setPw: React.Dispatch<React.SetStateAction<string>>,
appSizeOnLoad: number,
nodeChainId: string
nodeChainId: string,
}
export type NetworkingInfo = {

View File

@ -0,0 +1,130 @@
import { useState, useEffect, FormEvent, useCallback } from "react";
import { Link, useNavigate } from "react-router-dom";
import EnterKnsName from "../components/EnterKnsName";
import Loader from "../components/Loader";
import { PageProps } from "../lib/types";
import DirectCheckbox from "../components/DirectCheckbox";
import { Tooltip } from "../components/Tooltip";
import { useAccount, useWaitForTransactionReceipt, useWriteContract } from "wagmi";
import { useConnectModal, useAddRecentTransaction } from "@rainbow-me/rainbowkit"
import { dotOsAbi, DOTOS } from "../abis";
import { stringToHex, encodeAbiParameters, parseAbiParameters, keccak256 } from "viem";
interface RegisterOsNameProps extends PageProps { }
function CommitDotOsName({
direct,
setDirect,
setOsName,
setNetworkingKey,
setIpAddress,
setWsPort,
setTcpPort,
setRouters,
}: RegisterOsNameProps) {
let { address } = useAccount();
let navigate = useNavigate();
let { openConnectModal } = useConnectModal();
const { data: hash, writeContract, isPending, isError, error } = useWriteContract({
mutation: {
onSuccess: (data) => {
addRecentTransaction({ hash: data, description: `Pre-commit to .os ID: ${name}.os` });
}
}
});
const { isLoading: isConfirming, isSuccess: isConfirmed } =
useWaitForTransactionReceipt({
hash,
});
const addRecentTransaction = useAddRecentTransaction();
const [name, setName] = useState('')
const [nameValidities, setNameValidities] = useState<string[]>([])
const [triggerNameCheck, setTriggerNameCheck] = useState<boolean>(false)
useEffect(() => {
document.title = "Register"
}, [])
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [address])
const enterOsNameProps = { name, setName, nameValidities, setNameValidities, triggerNameCheck }
let handleCommit = useCallback(async (e: FormEvent) => {
e.preventDefault()
e.stopPropagation()
if (!address) {
openConnectModal?.()
return
}
console.log("committing to .os name: ", name)
const commitSecret = keccak256(stringToHex(name))
const commit = keccak256(
encodeAbiParameters(
parseAbiParameters('bytes32, bytes32'),
[keccak256(stringToHex(name)), commitSecret]
)
)
writeContract({
abi: dotOsAbi,
address: DOTOS,
functionName: 'commit',
args: [commit],
gas: 1000000n,
})
}, [name, direct, address, writeContract, setNetworkingKey, setIpAddress, setWsPort, setTcpPort, setRouters, openConnectModal])
useEffect(() => {
if (isConfirmed) {
setOsName(`${name}.os`);
navigate("/mint-os-name");
}
}, [isConfirmed, address, name, setOsName, navigate]);
return (
<div className="container fade-in">
<div className="section">
{Boolean(address) && (
<form className="form" onSubmit={handleCommit}>
{isPending || isConfirming ? (
<Loader msg={isConfirming ? 'Pre-committing to chosen ID...' : 'Please confirm the transaction in your wallet'} />
) : (
<>
<h3 className="form-label">
<Tooltip text="Kinodes need an onchain node identity in order to communicate with other nodes in the network.">
Choose a name for your Kinode
</Tooltip>
</h3>
<EnterKnsName {...enterOsNameProps} />
<DirectCheckbox {...{ direct, setDirect }} />
<div className="button-group">
<button
disabled={nameValidities.length !== 0 || isPending || isConfirming}
type="submit"
className="button"
>
Register .os name
</button>
<Link to="/reset" className="button secondary">
Already have a dot-os-name?
</Link>
</div>
</>
)}
{isError && (
<p className="error-message">
Error: {error?.message || 'There was an error registering your dot-os-name, please try again.'}
</p>
)}
</form>
)}
</div>
</div>
);
}
export default CommitDotOsName;

View File

@ -8,7 +8,7 @@ type OsHomeProps = {
function KinodeHome({ knsName }: OsHomeProps) {
const navigate = useNavigate()
const registerRedir = () => navigate('/register-name')
const registerRedir = () => navigate('/commit-os-name')
const resetRedir = () => navigate('/reset')
const importKeyfileRedir = () => navigate('/import-keyfile')
const loginRedir = () => navigate('/login')

View File

@ -0,0 +1,135 @@
import { useState, useEffect, FormEvent, useCallback } from "react";
import { useNavigate } from "react-router-dom";
import Loader from "../components/Loader";
import { PageProps } from "../lib/types";
import { useAccount, useWaitForTransactionReceipt, useSendTransaction } from "wagmi";
import { useConnectModal, useAddRecentTransaction } from "@rainbow-me/rainbowkit"
import { dotOsAbi, generateNetworkingKeys, KINO_ACCOUNT_IMPL, DOTOS } from "../abis";
import { encodePacked, encodeFunctionData, stringToHex, keccak256 } from "viem";
interface RegisterOsNameProps extends PageProps { }
function MintDotOsName({
direct,
knsName,
setNetworkingKey,
setIpAddress,
setWsPort,
setTcpPort,
setRouters,
}: RegisterOsNameProps) {
let { address } = useAccount();
let navigate = useNavigate();
let { openConnectModal } = useConnectModal();
const { data: hash, sendTransaction, isPending, isError, error } = useSendTransaction({
mutation: {
onSuccess: (data) => {
addRecentTransaction({ hash: data, description: `Mint ${knsName}` });
}
}
});
const { isLoading: isConfirming, isSuccess: isConfirmed } =
useWaitForTransactionReceipt({
hash,
});
const addRecentTransaction = useAddRecentTransaction();
const [triggerNameCheck, setTriggerNameCheck] = useState<boolean>(false)
useEffect(() => {
document.title = "Mint"
}, [])
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [address])
let handleMint = useCallback(async (e: FormEvent) => {
e.preventDefault()
e.stopPropagation()
if (!address) {
openConnectModal?.()
return
}
const initCall = await generateNetworkingKeys({
direct,
our_address: address,
label: knsName,
setNetworkingKey,
setIpAddress,
setWsPort,
setTcpPort,
setRouters,
reset: false,
});
console.log("minting name: ", knsName)
// strip .os suffix
const name = knsName.replace(/\.os$/, '');
const commitSecret = keccak256(stringToHex(name))
const data = encodeFunctionData({
abi: dotOsAbi,
functionName: 'mint',
args: [
address,
encodePacked(["bytes"], [stringToHex(name)]),
initCall,
"0x",
KINO_ACCOUNT_IMPL,
commitSecret
],
})
// use data to write to contract -- do NOT use writeContract
// writeContract will NOT generate the correct selector for some reason
// probably THEIR bug.. no abi works
try {
sendTransaction({
to: DOTOS,
data: data,
gas: 1000000n,
})
} catch (error) {
console.error('Failed to send transaction:', error)
}
}, [direct, address, sendTransaction, setNetworkingKey, setIpAddress, setWsPort, setTcpPort, setRouters, openConnectModal])
useEffect(() => {
if (isConfirmed) {
navigate("/set-password");
}
}, [isConfirmed, address, navigate]);
return (
<div className="container fade-in">
<div className="section">
{Boolean(address) && (
<form className="form" onSubmit={handleMint}>
{isPending || isConfirming ? (
<Loader msg={isConfirming ? 'Minting .os name...' : 'Please confirm the transaction in your wallet'} />
) : (
<>
<div className="button-group">
<button type="submit" className="button">
Mint pre-committed .os name
</button>
</div>
</>
)}
{isError && (
<p className="error-message">
Error: {error?.message || 'There was an error minting your dot-os-name, please try again.'}
</p>
)}
</form>
)}
</div>
</div>
);
}
export default MintDotOsName;

View File

@ -1,141 +0,0 @@
import { useState, useEffect, FormEvent, useCallback } from "react";
import { Link, useNavigate } from "react-router-dom";
import EnterKnsName from "../components/EnterKnsName";
import Loader from "../components/Loader";
import { PageProps } from "../lib/types";
import DirectCheckbox from "../components/DirectCheckbox";
import { Tooltip } from "../components/Tooltip";
import { useAccount, useWaitForTransactionReceipt, useWriteContract } from "wagmi";
import { useConnectModal, useAddRecentTransaction } from "@rainbow-me/rainbowkit"
import { kinomapAbi, generateNetworkingKeys, KINO_ACCOUNT_IMPL, DOTOS } from "../abis";
import { encodePacked, stringToHex } from "viem";
interface RegisterOsNameProps extends PageProps { }
function RegisterKnsName({
direct,
setDirect,
setOsName,
setNetworkingKey,
setIpAddress,
setWsPort,
setTcpPort,
setRouters,
}: RegisterOsNameProps) {
let { address } = useAccount();
let navigate = useNavigate();
let { openConnectModal } = useConnectModal();
const { data: hash, writeContract, isPending, isError, error } = useWriteContract({
mutation: {
onSuccess: (data) => {
addRecentTransaction({ hash: data, description: `Register KNS ID: ${name}.os` });
}
}
});
const { isLoading: isConfirming, isSuccess: isConfirmed } =
useWaitForTransactionReceipt({
hash,
});
const addRecentTransaction = useAddRecentTransaction();
const [name, setName] = useState('')
const [nameValidities, setNameValidities] = useState<string[]>([])
const [triggerNameCheck, setTriggerNameCheck] = useState<boolean>(false)
useEffect(() => {
document.title = "Register"
}, [])
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [address])
const enterOsNameProps = { name, setName, nameValidities, setNameValidities, triggerNameCheck }
let handleRegister = useCallback(async (e: FormEvent) => {
e.preventDefault()
e.stopPropagation()
if (!address) {
openConnectModal?.()
return
}
const initCall = await generateNetworkingKeys({
direct,
our_address: address,
label: name,
setNetworkingKey,
setIpAddress,
setWsPort,
setTcpPort,
setRouters,
reset: false,
});
writeContract({
abi: kinomapAbi,
address: DOTOS,
functionName: 'mint',
args: [
address,
encodePacked(["bytes"], [stringToHex(name)]),
initCall,
"0x",
KINO_ACCOUNT_IMPL,
],
gas: 1000000n,
})
}, [name, direct, address, writeContract, setNetworkingKey, setIpAddress, setWsPort, setTcpPort, setRouters, openConnectModal])
useEffect(() => {
if (isConfirmed) {
setOsName(`${name}.os`);
navigate("/set-password");
}
}, [isConfirmed, name, setOsName, navigate]);
return (
<div className="container fade-in">
<div className="section">
{Boolean(address) && (
<form className="form" onSubmit={handleRegister}>
{isPending || isConfirming ? (
<Loader msg={isConfirming ? 'Registering KNS ID...' : 'Please confirm the transaction in your wallet'} />
) : (
<>
<h3 className="form-label">
<Tooltip text="Kinodes need an onchain node identity in order to communicate with other nodes in the network.">
Choose a name for your Kinode
</Tooltip>
</h3>
<EnterKnsName {...enterOsNameProps} />
<DirectCheckbox {...{ direct, setDirect }} />
<div className="button-group">
<button
disabled={nameValidities.length !== 0 || isPending || isConfirming}
type="submit"
className="button"
>
Register .os name
</button>
<Link to="/reset" className="button secondary">
Already have a dot-os-name?
</Link>
</div>
</>
)}
{isError && (
<p className="error-message">
Error: {error?.message || 'There was an error registering your dot-os-name, please try again.'}
</p>
)}
</form>
)}
</div>
</div>
);
}
export default RegisterKnsName;

View File

@ -99,7 +99,8 @@ pub async fn register(
let react_app = warp::path::end()
.or(warp::path("login"))
.or(warp::path("register-name"))
.or(warp::path("commit-os-name"))
.or(warp::path("mint-os-name"))
.or(warp::path("claim-invite"))
.or(warp::path("reset"))
.or(warp::path("import-keyfile"))