Skip to content

Commit

Permalink
Update contract
Browse files Browse the repository at this point in the history
  • Loading branch information
yutou committed Apr 14, 2024
1 parent 0d57eb5 commit e03dbf1
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 56 deletions.
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"solidity.compileUsingRemoteVersion": "v0.8.24+commit.e11b9ed9",
"editor.formatOnSave": true,
"[solidity]": {
"editor.defaultFormatter": "JuanBlanco.solidity"
"editor.defaultFormatter": "NomicFoundation.hardhat-solidity"
},
"solidity.formatter": "forge"
}
}
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@

```bash
npx hardhat run scripts/01-deploy.ts --network sepolia
```
```


- a 发起 对 b 的求婚。a 可以发起多个求婚,但是同时只能有一个生效,第二次发起会把第一次发起的记录给清掉。
- b 可以看到所有对他发起的求婚的地址和信息,并选择其中一个地址进行确认。
- a 和 b 会创建一个 Attestation,之后 a 和 b 都不能再发起求婚或者确认求婚。
84 changes: 73 additions & 11 deletions scripts/01-deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import { ethers } from 'hardhat'

async function main() {

const [deployer, addressB] = await ethers.getSigners()
const [deployer, deployer2] = await ethers.getSigners()

const Factory = await ethers.getContractFactory('MarryMe')
const instance = await Factory.deploy()
const contract = await instance.waitForDeployment()
console.log(await contract.getAddress())

console.log('addressA:', deployer.getAddress())
console.log('addressB:', addressB.getAddress())
console.log('addressB:', deployer2.getAddress())

const addressA = await deployer.getAddress();
const addressB = await deployer2.getAddress();

await contract.setSPInstance('0x878c92FD89d8E0B93Dc0a3c907A2adc7577e39c5')

Expand All @@ -22,20 +25,79 @@ async function main() {
console.log('setSchemaID done')

// submitProposal

await contract.submitProposal(addressB.getAddress(), 'hello world B')
await (await contract.submitProposal(addressB, 'hello world B')).wait()

console.log('submitProposal done')

// acceptProposal

// switch to addressB to accept the proposal
await contract.connect(addressB).confirmProposal(deployer.getAddress(), 'hello world A')

console.log('acceptProposal done')

// 查询某个地址发送的所有求婚信息
const proposalSubmitted = await contract.getProposalsSentBy(addressA)
console.log('proposal submit by addressA:', JSON.stringify(proposalSubmitted, null, 2))

// 查询某个地址收到的所有求婚信息
const info = await contract.getProposalsReceivedBy(addressB);
console.log('proposal received by addressB:', JSON.stringify(info, null, 2))

// switch to addressB to accept the proposal
const confirm = await contract.connect(deployer2).confirmProposal(addressA, 'hello world A')
await confirm.wait()
console.log('acceptProposal done:')

// 查询某个地址的婚姻状态,返回 attestationId
const attestationId = await contract.getMarryAttestationId(addressA)
console.log('attestationID:', attestationId);

// 查询某个地址的婚姻状态,返回 attestation 详细信息
const attestation = await contract.getMarryAttestation(addressA);
console.log('attestation:', attestation)

// 查询某个地址的婚姻状态,返回 true/false
const isMarried = await contract.checkMarried(addressA)
console.log('isMarried:', isMarried)

/**
* output example:
*
0xE0B870ffbA7f73d5F757552F3a428DFE73431944
addressA: Promise { '0x9713093e7d93Eb303257c466e37440F9B5BE29f4' }
addressB: Promise { '0x5c1A1A6A86118820C58faF385291Ea9E83c1721C' }
setSPInstance done
setSchemaID done
submitProposal done
proposal submit by addressA: [
[
"0x5c1A1A6A86118820C58faF385291Ea9E83c1721C", "0x..."
],
[
"hello world B", "info for address 2"
]
]
proposal received by addressB: [
[
"0x9713093e7d93Eb303257c466e37440F9B5BE29f4"
],
[
"hello world B"
]
]
acceptProposal done:
attestationID: 55n
attestation: Result(10) [
7n,
0n,
1713090780n,
0n,
'0xE0B870ffbA7f73d5F757552F3a428DFE73431944',
0n,
0n,
false,
Result(2) [
'0x0000000000000000000000009713093e7d93eb303257c466e37440f9b5be29f4',
'0x0000000000000000000000005c1a1a6a86118820c58faf385291ea9e83c1721c'
],
'0x0000000000000000000000009713093e7d93eb303257c466e37440f9b5be29f40000000000000000000000005c1a1a6a86118820c58faf385291ea9e83c1721c000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d68656c6c6f20776f726c64204200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d68656c6c6f20776f726c64204100000000000000000000000000000000000000'
]
isMarried: true
*/

}

Expand Down
157 changes: 115 additions & 42 deletions src/MarryMe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,20 @@ contract MarryMe is Ownable {
ISP public spInstance;
uint64 public schemaId;

mapping(address => address) public proposalMapping;
mapping(address => string) public proposalInfo;
struct Proposal {
string info;
bool exists;
}

// Mapping from proposer to the proposee to their proposal info
mapping(address => mapping(address => Proposal)) public proposals;
// Mapping from proposer to an array of all proposees
mapping(address => address[]) private proposersToProposees;
// Mapping from proposee to an array of all proposers
mapping(address => address[]) private proposeesToProposers;

error ConfirmationAddressMismatch();
// marry result info, get attestationId by address
mapping(address => uint64) public attestationIdMapping;

event DidSignProposal(address addressA, address addressB, uint64 attestationId);

Expand All @@ -29,50 +39,113 @@ contract MarryMe is Ownable {
}

function submitProposal(address addressB, string memory infoA) external {
proposalMapping[_msgSender()] = addressB;
proposalInfo[_msgSender()] = infoA;
address addressA = _msgSender();
require(attestationIdMapping[addressA] == 0, "You have already married");

proposals[addressA][addressB] = Proposal({ info: infoA, exists: true });

proposersToProposees[addressA].push(addressB);
proposeesToProposers[addressB].push(addressA); // Store each proposer for the proposee
}

function cancelProposal(address addressB) external {
address addressA = _msgSender();
require(proposals[addressA][addressB].exists, "Proposal not found");

delete proposals[addressA][addressB];

// Remove proposee from proposer's array
for (uint256 i = 0; i < proposersToProposees[addressA].length; i++) {
if (proposersToProposees[addressA][i] == addressB) {
proposersToProposees[addressA][i] =
proposersToProposees[addressA][proposersToProposees[addressA].length - 1];
proposersToProposees[addressA].pop();
break;
}
}

// Remove proposer from proposee's array
for (uint256 i = 0; i < proposeesToProposers[addressB].length; i++) {
if (proposeesToProposers[addressB][i] == addressA) {
proposeesToProposers[addressB][i] =
proposeesToProposers[addressB][proposeesToProposers[addressB].length - 1];
proposeesToProposers[addressB].pop();
break;
}
}
}

function getProposalsSentBy(address proposer) external view returns (address[] memory, string[] memory) {
address[] memory proposees = proposersToProposees[proposer];
string[] memory infos = new string[](proposees.length);

for (uint256 i = 0; i < proposees.length; i++) {
infos[i] = proposals[proposer][proposees[i]].info;
}

return (proposees, infos);
}

function getProposalsReceivedBy(address proposee) external view returns (address[] memory, string[] memory) {
address[] memory proposers = proposeesToProposers[proposee];
string[] memory infos = new string[](proposers.length);

for (uint256 i = 0; i < proposers.length; i++) {
infos[i] = proposals[proposers[i]][proposee].info;
}

return (proposers, infos);
}

function getMarryAttestationId(address addr) external view returns (uint64) {
return attestationIdMapping[addr];
}

function getMarryAttestation(address addr) external view returns (Attestation memory) {
uint64 attestationId = attestationIdMapping[addr];
return spInstance.getAttestation(attestationId);
}

function checkMarried(address addr) external view returns (bool) {
return attestationIdMapping[addr] > 0;
}

function confirmProposal(address addressA, string memory infoB) external returns (uint64) {
// test schema: https://testnet-scan.sign.global/schema/onchain_evm_11155111_0x7
// real schema is : [{"name":"addressA","type":"address"},{"name":"addressB","type":"address"},{"name":"infoA","type":"string"},{"name":"infoB","type":"string"}]
address addressB = _msgSender();

console.log("addressA: ", addressA);
string memory infoA = proposalInfo[addressA];

console.log("addressB: ", addressB);

bytes memory data =
abi.encode(
addressA,
addressB,
infoA,
infoB
);

if (proposalMapping[addressA] == addressB) {
// B has confirm A's marriage proposal
bytes[] memory recipients = new bytes[](2);
recipients[0] = abi.encode(addressA);
recipients[1] = abi.encode(addressB);
Attestation memory a = Attestation({
schemaId: schemaId,
linkedAttestationId: 0,
attestTimestamp: 0,
revokeTimestamp: 0,
attester: address(this),
validUntil: 0,
dataLocation: DataLocation.ONCHAIN,
revoked: false,
recipients: recipients,
data: data
});
uint64 attestationId = spInstance.attest(a, "", "", "");
emit DidSignProposal(addressA, addressB, attestationId);
return attestationId;
} else {
revert ConfirmationAddressMismatch();
if (attestationIdMapping[addressA] > 0 || attestationIdMapping[addressB] > 0) {
revert("you have already married");
}

require(proposals[addressA][addressB].exists, "Proposal not found");

string memory infoA = proposals[addressA][addressB].info;

bytes memory data = abi.encode(addressA, addressB, infoA, infoB);
// B has confirm A's marriage proposal
bytes[] memory recipients = new bytes[](2);
recipients[0] = abi.encode(addressA);
recipients[1] = abi.encode(addressB);
Attestation memory a = Attestation({
schemaId: schemaId,
linkedAttestationId: 0,
attestTimestamp: 0,
revokeTimestamp: 0,
attester: address(this),
validUntil: 0,
dataLocation: DataLocation.ONCHAIN,
revoked: false,
recipients: recipients,
data: data
});
uint64 attestationId = spInstance.attest(a, "", "", "");

// mapping(address => uint64) public attestationIdMapping;
attestationIdMapping[addressA] = attestationId;
attestationIdMapping[addressB] = attestationId;

emit DidSignProposal(addressA, addressB, attestationId);

return attestationId;
}
}

0 comments on commit e03dbf1

Please sign in to comment.