Skip to content

Commit

Permalink
Add apis to get the status of ephe addr
Browse files Browse the repository at this point in the history
  • Loading branch information
SoraSuegami committed Jul 8, 2024
1 parent 8926a13 commit dbcb271
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 106 deletions.
14 changes: 14 additions & 0 deletions packages/relayer/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,20 @@ impl ChainClient {
Err(anyhow!("no EmailOpHandled event found in the receipt"))
}

pub async fn validate_ephe_addr(
&self,
wallet_addr: Address,
ephe_addr: Address,
nonce: U256,
) -> Result<()> {
let wallet_impl = self.account_handler.wallet_implementation().await?;
let wallet = WalletContract::new(wallet_impl, self.client.clone());
let oauth = IOauth::new(wallet.get_oauth().await?, self.client.clone());
let call = oauth.validate_ephe_addr(wallet_addr, ephe_addr, nonce);
call.call().await?;
Ok(())
}

pub async fn execute_ephemeral_tx(&self, tx: EphemeralTx) -> Result<String> {
// Mutex is used to prevent nonce conflicts.
let mut mutex = SHARED_MUTEX.lock().await;
Expand Down
52 changes: 52 additions & 0 deletions packages/relayer/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ impl Database {
.execute(&self.db)
.await?;

sqlx::query(
"CREATE TABLE IF NOT EXISTS ephe_addr_info (
request_id TEXT PRIMARY KEY,
wallet_addr TEXT NOT NULL,
ephe_addr TEXT NOT NULL,
nonce TEXT NOT NULL
);",
)
.execute(&self.db)
.await?;

Ok(())
}

Expand Down Expand Up @@ -432,4 +443,45 @@ impl Database {

Ok(result.is_some())
}

pub async fn get_ephe_addr_info(
&self,
request_id: &str,
) -> Result<Option<(String, String, String)>> {
let row = sqlx::query(
"SELECT email_address, ephe_addr, nonce FROM ephe_addr_info WHERE request_id = $1",
)
.bind(request_id)
.fetch_optional(&self.db)
.await?;

match row {
Some(row) => {
let wallet_addr: String = row.get("wallet_addr");
let ephe_addr: String = row.get("ephe_addr");
let nonce = row.get("nonce");
Ok(Some((wallet_addr, ephe_addr, nonce)))
}
None => Ok(None),
}
}

pub async fn insert_ephe_addr_info(
&self,
request_id: &str,
wallet_addr: &str,
ephe_addr: &str,
nonce: &str,
) -> Result<()> {
sqlx::query(
"INSERT INTO ephe_addr_info (request_id, wallet_addr, ephe_addr, nonce) VALUES ($1, $2, $3, $4) RETURNING *",
)
.bind(request_id)
.bind(wallet_addr)
.bind(ephe_addr)
.bind(nonce)
.fetch_one(&self.db)
.await?;
Ok(())
}
}
71 changes: 64 additions & 7 deletions packages/relayer/src/modules/web_server/rest_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@ use crate::{
EmailWalletEvent,
};
use ethers::{
etherscan::account,
types::{Address, Bytes, U256},
etherscan::account, types::{Address, Bytes, Signature, U256}, utils::{hash_message, keccak256}
};
use relayer_utils::{
converters::{field2hex, hex2field},
cryptos::{AccountCode, AccountSalt, PaddedEmailAddr},
ParsedEmail, LOG,
};

use crate::{CHAIN_RPC_EXPLORER, CLIENT, DB};
use crate::{CHAIN_RPC_EXPLORER, WEB_SERVER_ADDRESS,CLIENT, DB};
use hex::encode;
use rand::Rng;
use serde::{Deserialize, Serialize};
use serde_json::Number;
use serde_json::{from_str, Number};
use serde_json::Value;
use std::str::FromStr;

Expand Down Expand Up @@ -126,6 +124,20 @@ pub struct SignupOrInRequest {
// pub signature: String,
// }

#[derive(Serialize, Deserialize)]
pub struct EpheAddrStatusRequest {
pub request_id: String,
pub signature: String,
}

#[derive(Serialize, Deserialize)]
pub struct EpheAddrStatusResponse {
pub is_activated: bool,
pub wallet_addr: Option<String>,
pub nonce: Option<String>,
}


#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteEphemeralTxRequest {
pub wallet_addr: String,
Expand Down Expand Up @@ -471,7 +483,10 @@ pub async fn receive_email_api_fn(email: String) -> Result<()> {
}

pub async fn signup_or_in_api_fn(payload: String) -> Result<(u64, EmailMessage)> {
let request_id = rand::thread_rng().gen();
let mut request_id: u64 = rand::thread_rng().gen();
while DB.get_ephe_addr_info(&request_id.to_string()).await?.is_some() {
request_id = rand::thread_rng().gen();
}
let request = serde_json::from_str::<SignupOrInRequest>(&payload)
.map_err(|_| anyhow!("Invalid payload json".to_string()))?;
let account_code_str = DB.get_account_code(&request.email_addr).await?;
Expand Down Expand Up @@ -545,8 +560,9 @@ pub async fn signup_or_in_api_fn(payload: String) -> Result<(u64, EmailMessage)>
request
);
nonce = Some(got_nonce);
DB.insert_ephe_addr_info(&request_id.to_string(), &wallet_addr.to_string(),&ephe_addr.to_string(), &got_nonce.to_string()).await?;
}


let prefix = if is_signup { "Sign-up" } else { "Sign-in" };
let used_username = if is_signup {
Expand Down Expand Up @@ -662,6 +678,47 @@ pub async fn signup_or_in_api_fn(payload: String) -> Result<(u64, EmailMessage)>
// Ok(nonce)
// }

pub async fn ephe_addr_status_api_fn(payload: String) -> Result<EpheAddrStatusResponse> {
let request = serde_json::from_str::<EpheAddrStatusRequest>(&payload)
.map_err(|_| anyhow!("Invalid payload json".to_string()))?;
let ephe_addr_info = DB.get_ephe_addr_info(&request.request_id).await?;
let signature = Signature::from_str(&request.signature)?;
if ephe_addr_info.is_none() {
return Ok(EpheAddrStatusResponse {
is_activated: false,
wallet_addr: None,
nonce: None,
});
}
let (wallet_addr_str, ephe_addr_str, nonce) = ephe_addr_info.unwrap();
let wallet_addr = Address::from_str(&wallet_addr_str)?;
let ephe_addr = Address::from_str(&ephe_addr_str)?;
// verify if request.signature
let signed_msg = format!("{}/api/epheAddrStatus/{}", WEB_SERVER_ADDRESS.get().unwrap(),request.request_id);
let signed_msg_hash = hash_message(signed_msg);
let recovered_addr = signature.recover(signed_msg_hash)?;
if recovered_addr != ephe_addr {
return Ok(EpheAddrStatusResponse {
is_activated: false,
wallet_addr: None,
nonce: None,
});
}
if CLIENT.validate_ephe_addr(wallet_addr, ephe_addr, U256::from_str(&nonce)?).await.is_err() {
return Ok(EpheAddrStatusResponse {
is_activated: false,
wallet_addr: None,
nonce: None,
});
}

Ok(EpheAddrStatusResponse {
is_activated: true,
wallet_addr: Some(wallet_addr_str),
nonce: Some(nonce),
})
}

pub async fn execute_ephemeral_tx(payload: String) -> Result<String> {
let request = serde_json::from_str::<ExecuteEphemeralTxRequest>(&payload)
.map_err(|_| anyhow!("Invalid payload json".to_string()))?;
Expand Down
18 changes: 18 additions & 0 deletions packages/relayer/src/modules/web_server/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,24 @@ pub async fn run_server() -> Result<()> {
}
}),
)
.route("/api/epheAddrStatus",
axum::routing::post(move |payload: String| async move {
info!(LOG, "epheAddrStatus payload: {}", payload);
match ephe_addr_status_api_fn(payload).await {
Ok(res) => {
axum::Json(res)
}
Err(err) => {
error!(LOG, "Failed to accept signup: {}", err);
axum::Json(EpheAddrStatusResponse {
is_activated:false,
wallet_addr: None,
nonce: None,
})
}
}
}),
)
// .route(
// "/api/registerEpheAddr",
// axum::routing::post(move |payload: String| async move {
Expand Down
120 changes: 29 additions & 91 deletions packages/ts-sdk/src/oauthClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class OauthCore {
// accountCode: string | null = null;
userWallet: GetContractReturnType<typeof walletAbi, PublicClient> | null = null;
epheClient: PrivateKeyAccount;
// epheAddrNonce: bigint | null = null;
epheAddrNonce: string | null = null;


constructor(
Expand Down Expand Up @@ -48,98 +48,36 @@ export default class OauthCore {
username: string | null,
expiryTime: number | null,
tokenAllowances: [number, string][] | null
) {
): Promise<string> {
this.userEmailAddr = userEmailAddr;
await this.relayerApis.signupOrIn(userEmailAddr, this.epheClient.address, username, expiryTime, tokenAllowances);
return await this.relayerApis.signupOrIn(userEmailAddr, this.epheClient.address, username, expiryTime, tokenAllowances);
}

// public async loadAccountCode(
// accountCode: string
// ) {
// if (this.userEmailAddr === null) {
// throw new Error("Not setup yet")
// }
// const walletAddr = await this.relayerApis.getWalletAddress(this.userEmailAddr, accountCode);
// this.userWallet = getContract({
// address: walletAddr,
// abi: walletAbi,
// client: this.publicClient
// });
// }


// public async requestEmailAuthentication(
// userEmailAddr: string,
// ) {
// if (this.userEmailAddr !== null) {
// throw new Error("Already requested")
// }
// this.userEmailAddr = userEmailAddr;
// await this.relayerApis.recoverAccountCode(userEmailAddr);
// }

// public async completeEmailAuthentication(
// accountCode: string,
// ) {
// if (this.userEmailAddr === null) {
// throw new Error("Not requested yet")
// }
// if (this.accountCode !== null) {
// throw new Error("Already completed")
// }
// this.accountCode = accountCode;
// const walletAddr = await this.relayerApis.getWalletAddress(this.userEmailAddr, accountCode);
// this.userWallet = getContract({
// address: walletAddr,
// abi: walletAbi,
// client: this.publicClient
// });
// }
public async waitEpheAddrActivated(
requestId: string
): Promise<boolean> {
if (this.userEmailAddr === null) {
throw new Error("Not setup yet")
}
const signedMsg = `${this.relayerApis.relayerHost}/api/epheAddrStatus/${requestId}`;
const signature = await this.epheClient.signMessage({
message: signedMsg,
});

public async getOauthUsername(): Promise<string> {
if (this.userWallet === null) {
throw new Error("An account code is not loaded")
let res = await this.relayerApis.epheAddrStatus(requestId, signature);
while (!res.is_activated) {
await new Promise(resolve => setTimeout(resolve, 1000));
res = await this.relayerApis.epheAddrStatus(requestId, signature);
}
const username = await this.oauth.read.getUsernameOfWallet([this.userWallet.address]);
return username;
this.userWallet = getContract({
address: res.wallet_addr as `0x${string}`,
abi: walletAbi,
client: this.publicClient
});
this.epheAddrNonce = res.nonce as string;
return true;
}

// public async oauthSignup(
// username: string,
// nonce: string | null,
// expiry_time: number | null,
// token_allowances: [number, string][] | null
// ) {
// if (this.userEmailAddr === null || this.userWallet === null) {
// throw new Error("Not authenticated yet")
// }
// const requestId = await this.relayerApis.signup(this.userEmailAddr, username, nonce, expiry_time, token_allowances);
// console.log(`Request ID: ${requestId}`);
// }

// public async oauthSignin(
// expiry_time: number | null,
// token_allowances: [number, string][] | null
// ) {
// if (this.userEmailAddr === null || this.userWallet === null) {
// throw new Error("Not authenticated yet")
// }
// const username = await this.getOauthUsername();
// if (username === "") {
// throw new Error("Not signed up yet")
// }
// const epheAddr = this.epheClient.address;
// const chainId = await this.publicClient.getChainId();
// const signedMessageHash = encodePacked(["address", "uint256", "address", "string"], [this.oauth.address, BigInt(chainId), epheAddr, username]);
// const signature = await this.epheClient.signMessage({
// message: { raw: signedMessageHash },
// });
// const epheAddrNonce = await this.relayerApis.registerEpheAddr(this.userWallet.address, epheAddr, signature);
// this.epheAddrNonce = BigInt(epheAddrNonce);
// const requestId = await this.relayerApis.signin(this.userEmailAddr, username, epheAddrNonce, expiry_time, token_allowances);
// console.log(`Request ID: ${requestId}`);
// }

public async oauthExecuteTx(
target: Address,
data: `0x{string}`,
Expand All @@ -157,7 +95,7 @@ export default class OauthCore {
walletAddr: this.userWallet.address,
txNonce,
epheAddr: this.epheClient.address,
epheAddrNonce: this.epheAddrNonce,
epheAddrNonce: BigInt(this.epheAddrNonce),
target,
ethValue: ethValue === null ? 0n : ethValue,
data,
Expand All @@ -170,13 +108,13 @@ export default class OauthCore {
});
const txHash = await this.relayerApis.executeEphemeralTx(
tx.walletAddr,
tx.txNonce,
tx.txNonce.toString(),
tx.epheAddr,
tx.epheAddrNonce,
this.epheAddrNonce,
tx.target,
tx.ethValue,
tx.ethValue.toString(),
tx.data,
tx.tokenAmount,
tx.tokenAmount.toString(),
signature
);
return txHash;
Expand Down
Loading

0 comments on commit dbcb271

Please sign in to comment.