[WIP] Refactoring Logics

This commit is contained in:
HeesungB 2022-12-15 15:02:50 +09:00
parent 13de62028d
commit 7de3767d03
10 changed files with 179 additions and 118 deletions

View File

@ -0,0 +1,4 @@
export const TWITTER_LOGIN_ERROR = "Twitter login access denied";
export const TWITTER_PROFILE_ERROR = "Twitter auth code is not valid";
export const KEPLR_NOT_FOUND_ERROR = "Can't fount window.keplr";

View File

@ -2,14 +2,8 @@
import { useEffect, useState } from "react";
// Types
import {
ChainItemType,
IcnsVerificationResponse,
RegisteredAddresses,
TwitterAuthInfoResponse,
TwitterProfileType,
} from "../../types";
import { request } from "../../utils/url";
import { ChainItemType, TwitterProfileType } from "../../types";
import { checkTwitterAuthQueryParameter, request } from "../../utils/url";
// Styles
import styled from "styled-components";
@ -23,7 +17,6 @@ import { PrimaryButton } from "../../components/primary-button";
import { TwitterProfile } from "../../components/twitter-profile";
import { ChainList } from "../../components/chain-list";
import { useRouter } from "next/router";
import { ContractFee } from "../../constants/wallet";
import {
getKeplrFromWindow,
KeplrWallet,
@ -45,9 +38,17 @@ import {
import {
fetchTwitterInfo,
makeClaimMessage,
makeSetRecordMessage,
queryAddressesFromTwitterName,
queryRegisteredTwitterId,
verifyTwitterAccount,
} from "../../repository";
import { ErrorHandler } from "../../utils/error";
import {
KEPLR_NOT_FOUND_ERROR,
TWITTER_LOGIN_ERROR,
} from "../../constants/error-message";
export default function VerificationPage() {
const router = useRouter();
@ -65,37 +66,21 @@ export default function VerificationPage() {
const [allChecked, setAllChecked] = useState(false);
const [searchValue, setSearchValue] = useState("");
const fetchUrlQueryParameter = (): { state: string; code: string } => {
// Twitter state, auth code check
const [, state, code] =
window.location.search.match(
/^(?=.*state=([^&]+)|)(?=.*code=([^&]+)|).+$/,
) || [];
return {
state,
code,
};
};
useEffect(() => {
const init = async () => {
if (window.location.search) {
// Twitter Login Error Check
if (window.location.search.match("error")) {
await router.push("/");
return;
}
const { state, code } = fetchUrlQueryParameter();
try {
const { state, code } = checkTwitterAuthQueryParameter(
window.location.search,
);
// Initialize Wallet
await initWallet();
// Fetch Twitter Profile
const twitterInfo = await fetchTwitterInfo(state, code);
// check registered
const registeredQueryResponse = await queryRegisteredTwitterId(
twitterInfo.id,
);
@ -116,8 +101,12 @@ export default function VerificationPage() {
),
);
}
} catch (e) {
console.error(e);
} catch (error) {
if (error instanceof Error && error.message === TWITTER_LOGIN_ERROR) {
await router.push("/");
}
console.error(error);
} finally {
setIsLoading(false);
}
@ -127,15 +116,6 @@ export default function VerificationPage() {
init();
}, []);
const initWallet = async () => {
const keplr = await getKeplrFromWindow();
if (keplr) {
const keplrWallet = new KeplrWallet(keplr);
setWallet(keplrWallet);
}
};
useEffect(() => {
// After Wallet Initialize
if (wallet) {
@ -144,6 +124,7 @@ export default function VerificationPage() {
}, [wallet]);
useEffect(() => {
// To check registered chain
const filteredChainList = chainList.filter((chain) => {
return registeredAddressList.includes(chain.address);
});
@ -151,6 +132,17 @@ export default function VerificationPage() {
setCheckedItems(new Set(filteredChainList));
}, [registeredAddressList]);
const initWallet = async () => {
const keplr = await getKeplrFromWindow();
if (keplr) {
const keplrWallet = new KeplrWallet(keplr);
setWallet(keplrWallet);
} else {
ErrorHandler(KEPLR_NOT_FOUND_ERROR);
}
};
const fetchChainList = async () => {
if (wallet) {
const chainIds = (await wallet.getChainInfosWithoutEndpoints()).map(
@ -210,25 +202,6 @@ export default function VerificationPage() {
}
};
const verifyTwitterAccount = async (accessToken: string) => {
if (wallet) {
const key = await wallet.getKey(MainChainId);
return (
await request<IcnsVerificationResponse>("/api/icns-verification", {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
claimer: key.bech32Address,
authToken: accessToken,
}),
})
).verificationList;
}
};
const checkAdr36 = async () => {
if (twitterAuthInfo && wallet) {
const key = await wallet.getKey(MainChainId);
@ -237,7 +210,7 @@ export default function VerificationPage() {
return (chain as ChainItemType).chainId;
});
return await wallet.signICNSAdr36(
return wallet.signICNSAdr36(
MainChainId,
RESOLVER_ADDRESS,
key.bech32Address,
@ -248,59 +221,33 @@ export default function VerificationPage() {
};
const onClickRegistration = async () => {
const { state, code } = fetchUrlQueryParameter();
const { state, code } = checkTwitterAuthQueryParameter(
window.location.search,
);
const twitterInfo = await fetchTwitterInfo(state, code);
const adr36Infos = await checkAdr36();
const icnsVerificationList = await verifyTwitterAccount(
twitterInfo.accessToken,
);
if (wallet && icnsVerificationList && adr36Infos) {
if (wallet && adr36Infos) {
const key = await wallet.getKey(MainChainId);
const registerMsg = makeCosmwasmExecMsg(
const icnsVerificationList = await verifyTwitterAccount(
key.bech32Address,
REGISTRAR_ADDRESS,
{
claim: {
name: twitterInfo.username,
verifying_msg:
icnsVerificationList[0].status === "fulfilled"
? icnsVerificationList[0].value.data.verifying_msg
: "",
verifications: icnsVerificationList.map((verification) => {
if (verification.status === "fulfilled") {
return {
public_key: verification.value.data.public_key,
signature: verification.value.data.signature,
};
}
}),
},
},
[ContractFee],
twitterInfo.accessToken,
);
const registerMsg = makeClaimMessage(
key.bech32Address,
twitterInfo.username,
icnsVerificationList,
);
const addressMsgs = adr36Infos.map((adr36Info) => {
return makeCosmwasmExecMsg(
return makeSetRecordMessage(
key.bech32Address,
RESOLVER_ADDRESS,
{
set_record: {
name: twitterInfo.username,
bech32_prefix: adr36Info.bech32Prefix,
adr36_info: {
signer_bech32_address: adr36Info.bech32Address,
address_hash: adr36Info.addressHash,
pub_key: Buffer.from(adr36Info.pubKey).toString("base64"),
signature: Buffer.from(adr36Info.signature).toString("base64"),
signature_salt: adr36Info.signatureSalt.toString(),
},
},
},
[],
twitterInfo.username,
adr36Info,
);
});
@ -316,8 +263,6 @@ export default function VerificationPage() {
protoMsgs.push(addressMsg.proto);
}
console.log(aminoMsgs);
const chainInfo = {
chainId: MainChainId,
rest: REST_URL,
@ -348,7 +293,7 @@ export default function VerificationPage() {
},
);
router.push({
await router.push({
pathname: "complete",
query: { txHash: Buffer.from(txHash).toString("hex") },
});

View File

@ -7,9 +7,12 @@ import {
import { Buffer } from "buffer/";
import {
AddressesQueryResponse,
CosmwasmExecuteMessageResult,
NameByTwitterIdQueryResponse,
QueryError,
} from "../types";
import { makeCosmwasmExecMsg } from "../wallets";
import { ContractFee } from "../constants/wallet";
const getCosmwasmQueryUrl = (contractAddress: string, queryMsg: string) =>
`${REST_URL}/cosmwasm/wasm/v1/contract/${contractAddress}/smart/${queryMsg}`;
@ -34,10 +37,65 @@ export const queryAddressesFromTwitterName = async (
const msg = {
addresses: { name: twitterUsername },
};
return request<any>(
return request<AddressesQueryResponse>(
getCosmwasmQueryUrl(
RESOLVER_ADDRESS,
Buffer.from(JSON.stringify(msg)).toString("base64"),
),
);
};
export const makeClaimMessage = (
senderAddress: string,
twitterUserName: string,
verificationList: any[],
): CosmwasmExecuteMessageResult => {
return makeCosmwasmExecMsg(
senderAddress,
REGISTRAR_ADDRESS,
{
claim: {
name: twitterUserName,
verifying_msg:
verificationList[0].status === "fulfilled"
? verificationList[0].value.data.verifying_msg
: "",
verifications: verificationList.map((verification) => {
if (verification.status === "fulfilled") {
return {
public_key: verification.value.data.public_key,
signature: verification.value.data.signature,
};
}
}),
},
},
[ContractFee],
);
};
export const makeSetRecordMessage = (
senderAddress: string,
twitterUserName: string,
adr36Info: any,
): CosmwasmExecuteMessageResult => {
return makeCosmwasmExecMsg(
senderAddress,
RESOLVER_ADDRESS,
{
set_record: {
name: twitterUserName,
bech32_prefix: adr36Info.bech32Prefix,
adr36_info: {
signer_bech32_address: adr36Info.bech32Address,
address_hash: adr36Info.addressHash,
pub_key: Buffer.from(adr36Info.pubKey).toString("base64"),
signature: Buffer.from(adr36Info.signature).toString("base64"),
signature_salt: adr36Info.signatureSalt.toString(),
},
},
},
[],
);
};

View File

@ -1,4 +1,8 @@
import { TwitterAuthInfoResponse, TwitterAuthUrlResponse } from "../types";
import {
IcnsVerificationResponse,
TwitterAuthInfoResponse,
TwitterAuthUrlResponse,
} from "../types";
import { request } from "../utils/url";
export const loginWithTwitter = async () => {
@ -13,9 +17,25 @@ export const fetchTwitterInfo = async (
state: string,
code: string,
): Promise<TwitterAuthInfoResponse> => {
const newTwitterAuthInfo = await request<TwitterAuthInfoResponse>(
return await request<TwitterAuthInfoResponse>(
`/api/twitter-auth-info?state=${state}&code=${code}`,
);
return newTwitterAuthInfo;
};
export const verifyTwitterAccount = async (
claimer: string,
accessToken: string,
) => {
return (
await request<IcnsVerificationResponse>("/api/icns-verification", {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
claimer: claimer,
authToken: accessToken,
}),
})
).verificationList;
};

9
types/icns.ts Normal file
View File

@ -0,0 +1,9 @@
import { Any } from "@keplr-wallet/proto-types/google/protobuf/any";
export interface CosmwasmExecuteMessageResult {
amino: {
readonly type: string;
readonly value: any;
};
proto: Any;
}

View File

@ -3,3 +3,4 @@ export * from "./api-response";
export * from "./chain-item-type";
export * from "./msg";
export * from "./twitter";
export * from "./icns";

View File

@ -3,3 +3,8 @@ import { TwitterAuthInfoResponse } from "./api-response";
export interface TwitterProfileType extends TwitterAuthInfoResponse {
isRegistered: boolean;
}
export interface TwitterLoginSuccess {
code: string;
state: string;
}

3
utils/error.ts Normal file
View File

@ -0,0 +1,3 @@
export const ErrorHandler = (message: string) => {
console.error(message);
};

View File

@ -1,3 +1,6 @@
import { TwitterLoginSuccess } from "../types";
import { TWITTER_LOGIN_ERROR } from "../constants/error-message";
export function request<TResponse>(
url: string,
config: RequestInit = {},
@ -23,3 +26,21 @@ export function buildQueryString(query: Record<string, any>): string {
)
.join("&");
}
export const checkTwitterAuthQueryParameter = (
query: string,
): TwitterLoginSuccess => {
// Twitter Login Error Check
if (query.match("error")) {
throw new Error(TWITTER_LOGIN_ERROR);
}
// Twitter state, auth code check
const [, state, code] =
query.match(/^(?=.*state=([^&]+)|)(?=.*code=([^&]+)|).+$/) || [];
return {
state,
code,
};
};

View File

@ -15,6 +15,7 @@ import { Any } from "@keplr-wallet/proto-types/google/protobuf/any";
import { PubKey } from "@keplr-wallet/proto-types/cosmos/crypto/secp256k1/keys";
import { SignMode } from "@keplr-wallet/proto-types/cosmos/tx/signing/v1beta1/signing";
import { MsgExecuteContract } from "@keplr-wallet/proto-types/cosmwasm/wasm/v1/tx";
import { CosmwasmExecuteMessageResult } from "../types";
export async function sendMsgs(
wallet: Wallet,
@ -189,13 +190,7 @@ export function makeCosmwasmExecMsg(
// eslint-disable-next-line @typescript-eslint/ban-types
obj: object,
funds: { readonly amount: string; readonly denom: string }[],
): {
amino: {
readonly type: string;
readonly value: any;
};
proto: Any;
} {
): CosmwasmExecuteMessageResult {
const amino = {
type: "wasm/MsgExecuteContract",
value: {