-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
start init dynamic + otp email and jwt backend
- Loading branch information
Showing
16 changed files
with
409 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { constants } from 'starknet' | ||
|
||
type SupportedChainId = Exclude<constants.StarknetChainId, typeof constants.StarknetChainId.SN_GOERLI> | ||
|
||
type AddressesMap = Record<SupportedChainId, string> | ||
|
||
export const BLANK_ACCOUNT_CLASS_HASH = '0x1fa186ff7ea06307ded0baa1eb7648afc43618b92084da1110a9c0bd2b6bf56' | ||
|
||
export enum Entrypoint { | ||
DEPLOY_ACCOUNT = 'deploy_account', | ||
EXECUTE_FROM_OUTSIDE = 'execute_from_outside_v2', | ||
} | ||
|
||
export const VAULT_FACTORY_ADDRESSES: AddressesMap = { | ||
[constants.StarknetChainId.SN_MAIN]: '0x410da9af28e654fa93354430841ce7c5f0c2c17cc92971fb23d3d4f826d9834', | ||
[constants.StarknetChainId.SN_SEPOLIA]: '0x33498f0d9e6ebef71b3d8dfa56501388cfe5ce96cba81503cd8572be92bd77c', | ||
} | ||
|
||
export const DEFAULT_NETWORK_NAME = constants.NetworkName.SN_SEPOLIA | ||
|
||
// eslint-disable-next-line import/no-unused-modules | ||
export const SN_CHAIN_ID = (constants.StarknetChainId[(process.env.SN_NETWORK ?? '') as constants.NetworkName] ?? | ||
constants.StarknetChainId[DEFAULT_NETWORK_NAME]) as SupportedChainId | ||
|
||
// const NODE_URLS = { | ||
// [constants.StarknetChainId.SN_MAIN]: (apiKey: string) => `https://rpc.nethermind.io/mainnet-juno/?apikey=${apiKey}`, | ||
// [constants.StarknetChainId.SN_SEPOLIA]: (apiKey: string) => | ||
// `https://rpc.nethermind.io/sepolia-juno/?apikey=${apiKey}`, | ||
// } | ||
|
||
const NODE_URLS = { | ||
[constants.StarknetChainId.SN_MAIN]: (apiKey: string) => `https://starknet-sepolia.g.alchemy.com/v2/${apiKey}`, | ||
[constants.StarknetChainId.SN_SEPOLIA]: (apiKey: string) => | ||
`https://starknet-sepolia.g.alchemy.com/v2/${apiKey}`, | ||
} | ||
|
||
export const NODE_URL = NODE_URLS[SN_CHAIN_ID](process.env.RPC_NODE_API_KEY!) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import type { FastifyInstance } from 'fastify' | ||
import { VerificationListInstance } from 'twilio/lib/rest/verify/v2/service/verification' | ||
import { prisma } from "@prisma/client"; | ||
|
||
interface GetOtpRequestBody { | ||
phone_number: string | ||
nickname: string | ||
} | ||
|
||
async function getOtp(fastify: FastifyInstance, twilio_verification: VerificationListInstance) { | ||
fastify.post<{ Body: GetOtpRequestBody }>( | ||
'/get_otp', | ||
|
||
{ | ||
schema: { | ||
body: { | ||
type: 'object', | ||
required: ['phone_number', 'nickname'], | ||
properties: { | ||
phone_number: { type: 'string', pattern: '^\\+[1-9]\\d{1,14}$' }, | ||
nickname: { type: 'string', pattern: '^[A-Za-z]{1,20}$' }, | ||
}, | ||
}, | ||
}, | ||
}, | ||
|
||
async (request, reply) => { | ||
try { | ||
const { phone_number, nickname } = request.body | ||
|
||
// validating if phone number exists in db | ||
|
||
const record_by_phone_number = await prisma.registration.findFirst({ | ||
where:{ | ||
phoneNumber:phone_number | ||
}, | ||
orderBy: { created_at: "desc" }, | ||
|
||
}) | ||
|
||
if (!record_by_phone_number.length) { | ||
try { | ||
await prisma.registration.create({ | ||
data:{ | ||
phoneNumber:phone_number, | ||
nickname | ||
}, | ||
}) | ||
|
||
|
||
} catch (error: any) { | ||
fastify.log.error(error) | ||
if (error.code === '23505') { | ||
return reply.code(409).send({ | ||
message: 'A user with the given phone number already exists.', | ||
}) | ||
} | ||
return reply.code(500).send({ message: 'Internal server error' }) | ||
} | ||
} | ||
|
||
const send_msg_res = await twilio_verification.create({ | ||
to: phone_number, | ||
channel: 'sms', | ||
}) | ||
if (send_msg_res.status != 'pending') { | ||
fastify.log.error('Error sending message to phone number') | ||
return reply.code(500).send({ | ||
message: 'We are facing some issues. Please try again later', | ||
}) | ||
} | ||
|
||
return reply.code(200).send({ ok: true }) | ||
} catch (error) { | ||
fastify.log.error(error) | ||
return reply.code(500).send({ message: 'Internal Server Error' }) | ||
} | ||
}, | ||
) | ||
} | ||
|
||
export default getOtp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import type { FastifyInstance } from 'fastify' | ||
import { type Account, addAddressPadding, uint256 } from 'starknet' | ||
import { VerificationCheckListInstance } from 'twilio/lib/rest/verify/v2/service/verificationCheck' | ||
import { Entrypoint, SN_CHAIN_ID, VAULT_FACTORY_ADDRESSES } from '../../constants/contracts' | ||
import { hashPhoneNumber } from '../../utils/format' | ||
import { computeAddress } from '../../utils/address' | ||
import { prisma } from "@prisma/client"; | ||
|
||
|
||
interface VerifyOtpRequestBody { | ||
phone_number: string | ||
sent_otp: string | ||
public_key_x: string | ||
public_key_y: string | ||
} | ||
|
||
async function verifyOtp( | ||
fastify: FastifyInstance, | ||
deployer: Account, | ||
twilio_verification: VerificationCheckListInstance, | ||
) { | ||
fastify.post<{ | ||
Body: VerifyOtpRequestBody | ||
}>( | ||
'/verify_otp', | ||
|
||
{ | ||
schema: { | ||
body: { | ||
type: 'object', | ||
required: ['phone_number', 'public_key_x', 'public_key_y', 'sent_otp'], | ||
properties: { | ||
phone_number: { type: 'string', pattern: '^\\+[1-9]\\d{1,14}$' }, | ||
sent_otp: { type: 'string', pattern: '^[0-9]{6}$' }, | ||
public_key_x: { type: 'string', pattern: '^0x[0-9a-fA-F]+$' }, | ||
public_key_y: { type: 'string', pattern: '^0x[0-9a-fA-F]+$' }, | ||
}, | ||
}, | ||
}, | ||
}, | ||
|
||
async (request, reply) => { | ||
try { | ||
const { phone_number, sent_otp, public_key_x, public_key_y } = request.body | ||
|
||
// Create a verification request to twilio | ||
const response = await twilio_verification | ||
.create({ | ||
to: phone_number, | ||
code: sent_otp, | ||
}) | ||
.catch((error) => { | ||
fastify.log.error(error) | ||
return { status: 'unrequested' } | ||
}) | ||
|
||
// The status of the verification. Can be: `pending`, `approved`, `canceled`, `max_attempts_reached`, `deleted`, `failed` or `expired`. | ||
if (response.status != 'approved') { | ||
return reply.code(400).send({ | ||
message: `Otp is ${response.status}.`, | ||
}) | ||
} | ||
|
||
// check if user is already registered | ||
const user = prisma.registration.findFirst({ | ||
where: { | ||
phoneNumber: phone_number, | ||
} | ||
}) | ||
|
||
// user is already registered | ||
if (user?.is_confirmed) { | ||
return reply.code(200).send({ | ||
contract_address: user.contract_address, | ||
}) | ||
} | ||
|
||
// public key, approver, limit | ||
const { transaction_hash } = await deployer.execute({ | ||
contractAddress: VAULT_FACTORY_ADDRESSES[SN_CHAIN_ID], | ||
calldata: [ | ||
hashPhoneNumber(phone_number), | ||
uint256.bnToUint256(public_key_x), | ||
uint256.bnToUint256(public_key_y), | ||
], | ||
entrypoint: Entrypoint.DEPLOY_ACCOUNT, | ||
}) | ||
|
||
const contractAddress = addAddressPadding(computeAddress(phone_number)) | ||
|
||
fastify.log.info( | ||
'Deploying account: ', | ||
contractAddress, | ||
' for: ', | ||
phone_number, | ||
' with tx hash: ', | ||
transaction_hash, | ||
) | ||
|
||
if (!transaction_hash) { | ||
return reply.code(500).send({ | ||
message: 'Error in deploying smart contract. Please try again later', | ||
}) | ||
} | ||
|
||
// update the user record as confirmed and add the account address | ||
|
||
const userUpdated = await prisma.registration.update({ | ||
where: { | ||
phoneNumber: phone_number | ||
}, | ||
data: { | ||
is_confirmed: true, | ||
contract_address: contractAddress | ||
} | ||
}) | ||
// await fastify.db | ||
// .update(registration) | ||
// .set({ | ||
// is_confirmed: true, | ||
// contract_address: contractAddress, | ||
// }) | ||
// .where(eq(registration.phone_number, phone_number)) | ||
|
||
return reply.code(200).send({ | ||
contract_address: contractAddress, | ||
}) | ||
} catch (error) { | ||
console.log(error) | ||
fastify.log.error(error) | ||
return reply.code(500).send({ message: 'Internal Server Error' }) | ||
} | ||
}, | ||
) | ||
} | ||
|
||
export default verifyOtp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { hash } from 'starknet' | ||
import { hashPhoneNumber } from './format' | ||
import { BLANK_ACCOUNT_CLASS_HASH, SN_CHAIN_ID, VAULT_FACTORY_ADDRESSES } from '../constants/contracts' | ||
|
||
export function computeAddress(phoneNumber: string) { | ||
return hash.calculateContractAddressFromHash( | ||
hashPhoneNumber(phoneNumber), | ||
BLANK_ACCOUNT_CLASS_HASH, | ||
[], | ||
VAULT_FACTORY_ADDRESSES[SN_CHAIN_ID], | ||
) | ||
} |
Oops, something went wrong.