-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
d8e0cfc
commit 058ae1a
Showing
4 changed files
with
464 additions
and
0 deletions.
There are no files selected for viewing
219 changes: 219 additions & 0 deletions
219
...t/sdk-sample-app/src/components/zkevm/EthSendTransactionExamples/SeaportCreateListing.tsx
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,219 @@ | ||
import { utils } from 'ethers'; | ||
import React, { | ||
useCallback, useEffect, useMemo, useState, | ||
} from 'react'; | ||
import { | ||
Accordion, Alert, Form, Spinner, Stack, | ||
} from 'react-bootstrap'; | ||
import WorkflowButton from '@/components/WorkflowButton'; | ||
import { RequestExampleProps } from '@/types'; | ||
import { useImmutableProvider } from '@/context/ImmutableProvider'; | ||
import { usePassportProvider } from '@/context/PassportProvider'; | ||
import { | ||
ActionType, SignableAction, SignablePurpose, | ||
} from '@imtbl/orderbook'; | ||
|
||
type TokenType = 'NATIVE' | 'ERC20'; | ||
|
||
const { _TypedDataEncoder: typedDataEncoder } = utils; | ||
|
||
function SeaportCreateListing({ disabled, handleExampleSubmitted }: RequestExampleProps) { | ||
const { orderbookClient } = useImmutableProvider(); | ||
const { zkEvmProvider } = usePassportProvider(); | ||
|
||
const [walletAddress, setWalletAddress] = useState<string>(''); | ||
const [isBuldingTransaction, setIsBuildingTransaction] = useState<boolean>(false); | ||
const [transaction, setTransaction] = useState<any>(); | ||
const [transactionError, setSignMessageError] = useState<string>(''); | ||
|
||
const [NFTContractAddress, setNFTContractAddress] = useState<string>(''); | ||
const [tokenContractAddress, setTokenContractAddress] = useState<string>(''); | ||
const [buyAmount, setBuyAmount] = useState<string>(''); | ||
const [buyType, setBuyType] = useState<'NATIVE' | 'ERC20'>('NATIVE'); | ||
const [tokenId, setTokenId] = useState<string>(''); | ||
|
||
const seaportContractAddress = useMemo( | ||
() => ( | ||
orderbookClient.config().seaportContractAddress | ||
), | ||
[orderbookClient], | ||
); | ||
|
||
useEffect(() => { | ||
const getAddress = async () => { | ||
if (zkEvmProvider) { | ||
const [address] = await zkEvmProvider.request({ | ||
method: 'eth_requestAccounts', | ||
}); | ||
setWalletAddress(address || ''); | ||
} | ||
}; | ||
|
||
getAddress().catch(console.log); | ||
}, [zkEvmProvider, setWalletAddress]); | ||
|
||
useEffect(() => { | ||
setSignMessageError(''); | ||
setTransaction(undefined); | ||
}, [NFTContractAddress, tokenContractAddress, buyAmount, buyType, tokenId]); | ||
|
||
const validate = useCallback(async () => { | ||
const buy = buyType === 'NATIVE' | ||
? { amount: buyAmount, type: buyType } | ||
: { amount: buyAmount, type: buyType, contractAddress: tokenContractAddress }; | ||
try { | ||
setIsBuildingTransaction(true); | ||
const { actions } = await orderbookClient.prepareListing({ | ||
makerAddress: walletAddress, | ||
buy, | ||
sell: { | ||
contractAddress: NFTContractAddress, | ||
tokenId, | ||
type: 'ERC721', | ||
}, | ||
}); | ||
|
||
const signAction = actions.find((action) => ( | ||
action.type === ActionType.SIGNABLE && action.purpose === SignablePurpose.CREATE_LISTING | ||
)) as SignableAction | undefined; | ||
|
||
const populated = await typedDataEncoder.resolveNames( | ||
signAction!.message!.domain, | ||
signAction!.message!.types, | ||
signAction!.message!.value, | ||
(name: string) => Promise.resolve(name), | ||
); | ||
|
||
const payload = typedDataEncoder.getPayload(populated.domain, signAction!.message!.types, populated.value); | ||
setTransaction(payload); | ||
} catch (err) { | ||
setSignMessageError(`Failed to validate listing: ${err}`); | ||
} finally { | ||
setIsBuildingTransaction(false); | ||
} | ||
}, [NFTContractAddress, buyAmount, buyType, orderbookClient, tokenContractAddress, tokenId, walletAddress]); | ||
|
||
const handleSubmit = useCallback(async (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
|
||
return handleExampleSubmitted({ | ||
method: 'eth_signTypedData_v4', | ||
params: [walletAddress, transaction], | ||
}); | ||
}, [handleExampleSubmitted, transaction, walletAddress]); | ||
|
||
return ( | ||
<Accordion.Item eventKey="5"> | ||
<Accordion.Header>Seaport Create Listing</Accordion.Header> | ||
<Accordion.Body> | ||
<Alert variant="warning"> | ||
Note: This method only returns a signed message, it does not submit an order to the orderbook. | ||
</Alert> | ||
{transactionError | ||
&& ( | ||
<Alert variant="danger" style={{ wordBreak: 'break-word' }}> | ||
{transactionError} | ||
</Alert> | ||
)} | ||
<Form onSubmit={handleSubmit} className="mb-4"> | ||
<Form.Group className="mb-3"> | ||
<Form.Label> | ||
Seaport Contract Address | ||
</Form.Label> | ||
<Form.Control | ||
required | ||
disabled | ||
type="text" | ||
value={seaportContractAddress} | ||
/> | ||
</Form.Group> | ||
<Form.Group className="mb-3"> | ||
<Form.Label> | ||
NFT Contract Address | ||
</Form.Label> | ||
<Form.Control | ||
required | ||
type="text" | ||
value={NFTContractAddress} | ||
isValid={transaction && !transactionError} | ||
isInvalid={!!transactionError} | ||
onChange={(e) => setNFTContractAddress(e.target.value)} | ||
/> | ||
</Form.Group> | ||
<Form.Group className="mb-3"> | ||
<Form.Label> | ||
Token ID | ||
</Form.Label> | ||
<Form.Control | ||
required | ||
type="number" | ||
value={tokenId} | ||
isValid={transaction && !transactionError} | ||
isInvalid={!!transactionError} | ||
onChange={(e) => setTokenId(e.target.value)} | ||
/> | ||
</Form.Group> | ||
<Form.Group className="mb-3"> | ||
<Form.Label> | ||
Currency Type | ||
</Form.Label> | ||
<Form.Select | ||
required | ||
value={buyType} | ||
onChange={(e) => setBuyType(e.target.value as TokenType)} | ||
> | ||
<option value="NATIVE">Native</option> | ||
<option value="ERC20">ERC20</option> | ||
</Form.Select> | ||
</Form.Group> | ||
{buyType === 'ERC20' && ( | ||
<Form.Group className="mb-3"> | ||
<Form.Label> | ||
Currency Contract Address | ||
</Form.Label> | ||
<Form.Control | ||
required | ||
value={tokenContractAddress} | ||
isValid={transaction && !transactionError} | ||
isInvalid={!!transactionError} | ||
onChange={(e) => setTokenContractAddress(e.target.value)} | ||
/> | ||
</Form.Group> | ||
)} | ||
<Form.Group className="mb-3"> | ||
<Form.Label> | ||
Currency Amount | ||
</Form.Label> | ||
<Form.Control | ||
required | ||
type="text" | ||
value={buyAmount} | ||
isValid={transaction && !transactionError} | ||
isInvalid={!!transactionError} | ||
onChange={(e) => setBuyAmount(e.target.value)} | ||
/> | ||
</Form.Group> | ||
<Stack direction="horizontal" gap={3}> | ||
<WorkflowButton | ||
disabled={disabled || isBuldingTransaction || !!transaction || !!transactionError} | ||
type="button" | ||
onClick={validate} | ||
> | ||
Validate | ||
</WorkflowButton> | ||
<WorkflowButton | ||
disabled={disabled || !transaction} | ||
type="submit" | ||
> | ||
Submit | ||
</WorkflowButton> | ||
{ isBuldingTransaction && <Spinner /> } | ||
</Stack> | ||
</Form> | ||
</Accordion.Body> | ||
</Accordion.Item> | ||
); | ||
} | ||
|
||
export default SeaportCreateListing; |
85 changes: 85 additions & 0 deletions
85
...ample-app/src/components/zkevm/EthSendTransactionExamples/SeaportCreateListingDefault.tsx
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,85 @@ | ||
import React, { | ||
useCallback, useEffect, useMemo, useState, | ||
} from 'react'; | ||
import { | ||
Accordion, Alert, Form, Stack, | ||
} from 'react-bootstrap'; | ||
import WorkflowButton from '@/components/WorkflowButton'; | ||
import { RequestExampleProps } from '@/types'; | ||
import { useImmutableProvider } from '@/context/ImmutableProvider'; | ||
import { usePassportProvider } from '@/context/PassportProvider'; | ||
import { getCreateListingPayload } from './SeaportCreateListingExample'; | ||
|
||
function SeaportCreateListingDefault({ disabled, handleExampleSubmitted }: RequestExampleProps) { | ||
const { orderbookClient } = useImmutableProvider(); | ||
const { zkEvmProvider } = usePassportProvider(); | ||
|
||
const [params, setParams] = useState<any>(); | ||
|
||
const seaportContractAddress = useMemo( | ||
() => ( | ||
orderbookClient.config().seaportContractAddress | ||
), | ||
[orderbookClient], | ||
); | ||
|
||
useEffect(() => { | ||
const getAddress = async () => { | ||
if (zkEvmProvider) { | ||
const [address] = await zkEvmProvider.request({ | ||
method: 'eth_requestAccounts', | ||
}); | ||
const chainIdHex = await zkEvmProvider.request({ method: 'eth_chainId' }); | ||
const chainId = parseInt(chainIdHex, 16); | ||
const data = getCreateListingPayload({ seaportContractAddress, walletAddress: address, chainId }); | ||
setParams([address, data]); | ||
} | ||
}; | ||
getAddress().catch(console.log); | ||
}, [zkEvmProvider, seaportContractAddress]); | ||
|
||
const handleSubmit = useCallback(async (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
|
||
return handleExampleSubmitted({ | ||
method: 'eth_signTypedData_v4', | ||
params, | ||
}); | ||
}, [handleExampleSubmitted, params]); | ||
|
||
return ( | ||
<Accordion.Item eventKey="4"> | ||
<Accordion.Header>Seaport Create Listing (Hardcoded example)</Accordion.Header> | ||
<Accordion.Body> | ||
<Alert variant="warning"> | ||
Note: This method only returns a signed message, it does not submit an order to the orderbook. | ||
</Alert> | ||
<Form onSubmit={handleSubmit} className="mb-4"> | ||
<Form.Group className="mb-3"> | ||
<Form.Label> | ||
Preview | ||
</Form.Label> | ||
<Form.Control | ||
required | ||
disabled | ||
as="textarea" | ||
rows={7} | ||
value={JSON.stringify(params, null, '\t')} | ||
/> | ||
</Form.Group> | ||
<Stack direction="horizontal" gap={3}> | ||
<WorkflowButton | ||
disabled={disabled} | ||
type="submit" | ||
> | ||
Submit | ||
</WorkflowButton> | ||
</Stack> | ||
</Form> | ||
</Accordion.Body> | ||
</Accordion.Item> | ||
); | ||
} | ||
|
||
export default SeaportCreateListingDefault; |
Oops, something went wrong.